diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e0df515 --- /dev/null +++ b/.env.example @@ -0,0 +1,15 @@ +# Copy to `.env` (or set via your shell) to enable optional integrations. +# `.env`, `.env.local`, and `.env.production` are all gitignored. +# +# Both of these values are PUBLIC (they're shipped to the browser by Astro's +# `envField`, and live behind rate limiting / allow-lists on the vendor side). + +# Kapa Custom Frontend integration ID for the "Ask AI" button in the header. +# If unset, the Ask AI button is hidden and the site still runs normally. +# Get yours at: https://app.kapa.ai/admin +PUBLIC_KAPA_INTEGRATION_ID= + +# PushFeedback project ID for the per-page "Was this helpful?" widget and the +# feedback widget on the Scalar API page. If unset, both widgets are hidden. +# Dashboard: https://app.pushfeedback.com +PUBLIC_PUSHFEEDBACK_PROJECT_ID= diff --git a/.github/ISSUE_TEMPLATE/BUGS.yml b/.github/ISSUE_TEMPLATE/BUGS.yml new file mode 100644 index 0000000..0869f98 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUGS.yml @@ -0,0 +1,52 @@ +name: "Docs site bug" +description: Report a problem with the docs website, not the documentation content. +labels: + - bug +body: + - type: textarea + id: description + attributes: + label: Issue description + description: Describe the problem you experienced while using the Warp Docs website. + placeholder: The page does not load, search is not working, navigation is broken, etc. + validations: + required: true + - type: textarea + id: pages + attributes: + label: Page or pages affected + description: Provide the URL of each page where the issue occurs. + placeholder: https://docs.warp.dev/getting-started/quickstart/installation-and-setup + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected behavior + description: Describe what you expected to happen. + placeholder: I expected... + validations: + required: true + - type: textarea + id: actual + attributes: + label: Actual behavior + description: Describe what happened instead. + placeholder: Instead... + validations: + required: true + - type: input + id: browser + attributes: + label: Browser + description: Include your browser and version if the issue appears browser-specific. + placeholder: Chrome 124, Safari 17, Firefox 125, etc. + validations: + required: false + - type: textarea + id: additional + attributes: + label: Additional context + description: Add screenshots, recordings, error messages, or other details that may help us investigate. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/CONTENT.yml b/.github/ISSUE_TEMPLATE/CONTENT.yml new file mode 100644 index 0000000..256d070 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/CONTENT.yml @@ -0,0 +1,40 @@ +name: "Docs content issue" +description: Report incorrect, outdated, missing, or unclear documentation. +labels: + - improve or update documentation +body: + - type: markdown + attributes: + value: "Minor fixes like typos, broken links, and short clarifications can go straight to a pull request." + - type: input + id: subject + attributes: + label: Subject area or topic + description: Which product area or documentation topic does this affect? + placeholder: Agent Mode, Warp Drive, cloud agents, API keys, billing, etc. + validations: + required: true + - type: textarea + id: pages + attributes: + label: Page or pages affected + description: Provide the URL of each affected page, or suggest where new content should live. + placeholder: https://docs.warp.dev/agent-platform/capabilities/skills + validations: + required: true + - type: textarea + id: problem + attributes: + label: What is incorrect, outdated, missing, or unclear? + description: Describe the documentation problem and why it matters. + placeholder: This page says..., but the current behavior is... + validations: + required: true + - type: textarea + id: suggested + attributes: + label: Suggested update + description: Share the correction, source context, or proposed direction if you have one. + placeholder: The page should say... + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..ea61216 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Ask the Warp community + url: https://go.warp.dev/join-preview + about: This issue tracker is not for support questions. Join the Warp community Slack for help. + - name: Read the contribution guide + url: https://github.com/warpdotdev/docs/blob/main/CONTRIBUTING.md + about: Learn how to contribute to Warp Docs. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..aae63bd --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,19 @@ +## Summary + + + +## Related issues + + + +## Validation + + + +## Screenshots + + + +## Follow-ups + + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..2557fd6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,46 @@ +name: CI + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + build: + name: Build, link-check, audit + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + cache: 'npm' + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install dependencies + run: npm ci + + - name: Type-check + run: npm run typecheck + + - name: Build site + run: npm run build + + - name: Check internal links + run: python3 .warp/skills/check_for_broken_links/check_links.py --internal-only + + # Production-only audit; gate on high+ so dev-only deprecation chatter + # doesn't break PRs. The `|| true` keeps it informational; tighten this + # to a hard fail once we're confident the noise is gone. + - name: npm audit (production deps) + run: npm audit --omit=dev --audit-level=high || true diff --git a/.github/workflows/respond-to-comment.yml b/.github/workflows/respond-to-comment.yml new file mode 100644 index 0000000..4d87a86 --- /dev/null +++ b/.github/workflows/respond-to-comment.yml @@ -0,0 +1,249 @@ +name: Respond to Comment +on: + issue_comment: + types: + - created + pull_request_review_comment: + types: + - created +jobs: + respond: + runs-on: ubuntu-latest + if: | + contains(github.event.comment.body,'@oz-agent') && + ( + github.event_name == 'pull_request_review_comment' || + (github.event_name == 'issue_comment' && github.event.issue.pull_request) + ) && + github.actor != 'github-actions[bot]' + permissions: + contents: write + pull-requests: write + issues: write + steps: + - name: Check author permissions + uses: actions/github-script@v7 + with: + github-token: ${{ github.token }} + script: | + const { data } = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: context.repo.owner, + repo: context.repo.repo, + username: context.payload.comment.user.login, + }); + if (!['admin', 'write'].includes(data.permission)) { + core.setFailed(`Comment author @${context.payload.comment.user.login} lacks write access (has '${data.permission}')`); + } + - name: Checkout Action + uses: actions/checkout@v4 + - name: Acknowledge Comment + env: + GH_TOKEN: ${{ github.token }} + run: | + COMMENT_ID="${{ github.event.comment.id }}" + REACTION="eyes" + + if [ "${{ github.event_name }}" == "pull_request_review_comment" ]; then + gh api \ + --method POST \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + /repos/${{ github.repository }}/pulls/comments/$COMMENT_ID/reactions \ + -f content="$REACTION" + else + gh api \ + --method POST \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + /repos/${{ github.repository }}/issues/comments/$COMMENT_ID/reactions \ + -f content="$REACTION" + fi + - name: Checkout PR + env: + GH_TOKEN: ${{ github.token }} + run: | + PR_NUMBER="${{ github.event.issue.number }}" + if [ -z "$PR_NUMBER" ]; then + PR_NUMBER="${{ github.event.pull_request.number }}" + fi + + echo "Checking out PR #$PR_NUMBER" + gh pr checkout "$PR_NUMBER" + - name: Construct Prompt + id: prompt + uses: actions/github-script@v7 + with: + github-token: ${{ github.token }} + script: | + const { owner, repo } = context.repo; + let prNumber; + if (context.eventName === 'issue_comment') { + prNumber = context.payload.issue.number; + } else { + prNumber = context.payload.pull_request.number; + } + + // Fetch PR details to provide full context + const { data: pr } = await github.rest.pulls.get({ + owner, + repo, + pull_number: prNumber, + }); + + // Get the list of files changed in the PR + const { data: files } = await github.rest.pulls.listFiles({ + owner, + repo, + pull_number: prNumber, + }); + + const fileList = files.map(f => f.filename).join(', '); + + const commentBody = context.payload.comment.body; + const author = context.payload.comment.user.login; + + let prompt = `You are an expert software engineer and the Oz Agent. + You are responding to a specific request on a Pull Request. This may involve answering questions, providing explanations, or implementing code changes. + + **Context**: + - **PR Title**: ${pr.title} + - **PR Description**: ${pr.body || 'No description provided.'} + - **Changed Files**: ${fileList} + - **User Request**: "${commentBody}" (from user @${author}) + `; + + if (context.eventName === 'pull_request_review_comment') { + const path = context.payload.comment.path; + const line = context.payload.comment.line; + const diffHunk = context.payload.comment.diff_hunk; + prompt += ` + - **Location**: File '${path}' at line ${line}. + - **Diff Context**: + \`\`\`diff + ${diffHunk} + \`\`\` + `; + prompt += ` + **Instructions**: + 1. Read the file at '${path}' to understand the full context around the line. + `; + } else { + prompt += ` + **Instructions**: + 1. Focus your analysis on the changed files (${fileList}) unless the request explicitly mentions other files. + `; + } + + prompt += `2. Determine if the user is asking a question or requesting code changes. + 3. If asking a question: Answer it based on your analysis of the code and context. + 4. If requesting code changes: Implement them carefully, ensuring correctness and following existing style. + 5. Do not output code diffs in your final message; only provide a clear explanation of what you did or answered. + 6. Format your response in Markdown. + 7. Your output will be posted as a reply to the user. + 8. Do not attempt to stage or commit changes manually. This happens automatically after you complete your response. + `; + + core.setOutput('prompt', prompt); + - name: Run Oz Agent + uses: warpdotdev/oz-agent-action@v1 + env: + GH_TOKEN: ${{ github.token }} + id: agent + with: + prompt: ${{ steps.prompt.outputs.prompt }} + warp_api_key: ${{ secrets.WARP_API_KEY }} + profile: '' + output_format: json + model: '' + name: '' + mcp: '' + - name: Commit and Push Changes + if: success() + env: + GH_TOKEN: ${{ github.token }} + run: | + git config user.name "Oz Agent" + git config user.email "agent@warp.dev" + + if [[ -n $(git status --porcelain) ]]; then + git add . + git commit -m "Oz Agent: Address comment" + git push + else + echo "No changes to commit." + fi + - name: Reply to Comment + if: success() + uses: actions/github-script@v7 + env: + AGENT_OUTPUT: ${{ steps.agent.outputs.agent_output }} + with: + github-token: ${{ github.token }} + script: | + const raw = process.env.AGENT_OUTPUT || ''; + + // Walk JSONL lines and capture the last agent text message, if any. + let lastText = ''; + for (const line of raw.split('\n')) { + const trimmed = line.trim(); + if (!trimmed) continue; + try { + const obj = JSON.parse(trimmed); + if (obj.type === 'agent' && typeof obj.text === 'string') { + lastText = obj.text; + } + } catch (e) { + // Ignore non-JSON lines + } + } + + const content = (lastText || raw || '').trim(); + if (!content) { + core.info('No agent output to reply with.'); + return; + } + + const body = `@${context.payload.comment.user.login}: ${content}`; + const { owner, repo } = context.repo; + + if (context.eventName === 'pull_request_review_comment') { + await github.rest.pulls.createReplyForReviewComment({ + owner, + repo, + pull_number: context.payload.pull_request.number, + comment_id: context.payload.comment.id, + body, + }); + } else { + await github.rest.issues.createComment({ + owner, + repo, + issue_number: context.payload.issue.number, + body, + }); + } + - name: Report Agent Error + if: failure() && steps.agent.outcome == 'failure' + uses: actions/github-script@v7 + with: + github-token: ${{ github.token }} + script: | + const body = `@${context.payload.comment.user.login}: ⚠️ I encountered an error while processing your request. Please check the [workflow run logs] for more details.`; + const { owner, repo } = context.repo; + + if (context.eventName === 'pull_request_review_comment') { + await github.rest.pulls.createReplyForReviewComment({ + owner, + repo, + pull_number: context.payload.pull_request.number, + comment_id: context.payload.comment.id, + body, + }); + } else { + await github.rest.issues.createComment({ + owner, + repo, + issue_number: context.payload.issue.number, + body, + }); + } diff --git a/.github/workflows/review-pr.yml b/.github/workflows/review-pr.yml new file mode 100644 index 0000000..772db56 --- /dev/null +++ b/.github/workflows/review-pr.yml @@ -0,0 +1,196 @@ +name: Auto PR Review + +on: + pull_request: + types: [opened, ready_for_review] + +jobs: + review_pr: + if: github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + issues: write + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Review PR with Oz agent + uses: warpdotdev/oz-agent-action@v1 + env: + GH_TOKEN: ${{ github.token }} + with: + warp_api_key: ${{ secrets.WARP_API_KEY }} + skill: review-docs-pr + + - name: Post Review + uses: actions/github-script@v7 + if: always() + with: + script: | + const fs = require('fs'); + const { owner, repo } = context.repo; + const prNumber = context.payload.pull_request.number; + const commitSha = context.payload.pull_request.head.sha; + + try { + if (!fs.existsSync('review.json')) { + console.log('No review.json found. Skipping review posting.'); + return; + } + + const reviewContent = fs.readFileSync('review.json', 'utf8'); + + let review; + try { + review = JSON.parse(reviewContent); + } catch (parseError) { + core.warning(`Failed to parse review.json: ${parseError.message}`); + const sanitized = reviewContent.replace(/[\u0000-\u001F]+/g, ' '); + try { + review = JSON.parse(sanitized); + } catch (sanitizedError) { + core.setFailed(`Failed to parse review.json even after sanitizing: ${sanitizedError.message}`); + return; + } + } + + const decodeNewlines = (text) => { + if (typeof text !== 'string') return text; + return text.replace(/\r\n/g, '\n').replace(/\\n/g, '\n'); + }; + + const rawComments = Array.isArray(review.comments) ? review.comments : []; + + // Fetch valid file paths from the PR + const prFiles = await github.paginate( + github.rest.pulls.listFiles, + { owner, repo, pull_number: prNumber } + ); + const validPaths = new Set(prFiles.map(f => f.filename)); + + // Build a map of valid diff line numbers per file and side. + // GitHub's createReview API only accepts line numbers that appear + // in the PR diff; comments targeting other lines cause a 422. + const validLines = new Map(); // key: "path:side" -> Set of line numbers + for (const file of prFiles) { + if (!file.patch) continue; + const rightLines = new Set(); + const leftLines = new Set(); + let oldLine = 0; + let newLine = 0; + for (const raw of file.patch.split('\n')) { + const hunkHeader = raw.match(/^@@ -(?:\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/); + if (hunkHeader) { + const parts = raw.match(/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/); + oldLine = parseInt(parts[1], 10); + newLine = parseInt(parts[2], 10); + continue; + } + if (raw.startsWith('+')) { + rightLines.add(newLine); + newLine++; + } else if (raw.startsWith('-')) { + leftLines.add(oldLine); + oldLine++; + } else { + // Context line — valid on both sides + rightLines.add(newLine); + leftLines.add(oldLine); + newLine++; + oldLine++; + } + } + validLines.set(`${file.filename}:RIGHT`, rightLines); + validLines.set(`${file.filename}:LEFT`, leftLines); + } + + const comments = []; + const displaced = []; // comments whose lines aren't in the diff + + for (const c of rawComments) { + if (!c || typeof c !== 'object') continue; + if (typeof c.body !== 'string' || !c.body.trim()) continue; + if (typeof c.path !== 'string' || !c.path.trim()) continue; + + // Normalize path + const normalizedPath = c.path.trim() + .replace(/^([ab]\/)*/, '') + .replace(/^\.\//, ''); + + if (!validPaths.has(normalizedPath)) { + console.log(`Skipping comment with invalid path: ${c.path} -> ${normalizedPath}`); + continue; + } + + const line = Number(c.line); + if (!Number.isInteger(line) || line <= 0) { + console.log('Skipping comment with invalid line:', c); + continue; + } + + let side = (c.side || 'RIGHT').toString().toUpperCase(); + if (side !== 'LEFT' && side !== 'RIGHT') { + console.log(`Invalid side '${c.side}', defaulting to RIGHT`); + side = 'RIGHT'; + } + + const body = decodeNewlines(c.body); + + // Validate that this line number exists in the diff for this file/side + const key = `${normalizedPath}:${side}`; + const lineSet = validLines.get(key); + if (!lineSet || !lineSet.has(line)) { + console.log(`Comment targets line ${line} (${side}) in ${normalizedPath} which is outside the diff — moving to summary.`); + displaced.push({ path: normalizedPath, line, side, body }); + continue; + } + + comments.push({ path: normalizedPath, line, side, body }); + } + + let summary = typeof review.summary === 'string' ? decodeNewlines(review.summary).trim() : ''; + + // Append displaced comments to the summary so feedback isn't lost + if (displaced.length > 0) { + const extra = displaced.map(d => + `**${d.path}** (line ${d.line}):\n${d.body}` + ).join('\n\n---\n\n'); + const header = '\n\n---\n\n**Additional comments** (targeting lines outside the diff):\n\n'; + summary = summary ? summary + header + extra : header.trimStart() + extra; + } + const hasSummary = summary.length > 0; + + if (!hasSummary && comments.length === 0) { + console.log('No valid summary or inline comments found. Skipping review posting.'); + return; + } + + const payload = { + owner, + repo, + pull_number: prNumber, + commit_id: commitSha, + event: 'COMMENT', + }; + + if (hasSummary) { + payload.body = summary; + } else { + payload.body = 'Automated review by Oz Agent'; + } + + if (comments.length > 0) { + payload.comments = comments; + } + + await github.rest.pulls.createReview(payload); + + console.log('Review posted successfully.'); + + } catch (error) { + console.error('Failed to post review:', error); + core.setFailed(`Failed to post review: ${error.message}`); + } diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c52c01d --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# build output +dist/ +.vercel/ +# generated types +.astro/ + +# dependencies +node_modules/ + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store +__pycache__/ +.vercel +.env*.local diff --git a/.trunk/.gitignore b/.trunk/.gitignore new file mode 100644 index 0000000..8130ba6 --- /dev/null +++ b/.trunk/.gitignore @@ -0,0 +1,8 @@ +*out +*logs +*actions +*notifications +plugins +user_trunk.yaml +user.yaml +shims diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml new file mode 100644 index 0000000..1c23d1c --- /dev/null +++ b/.trunk/trunk.yaml @@ -0,0 +1,30 @@ +version: 0.1 +cli: + version: 1.10.0 +plugins: + sources: + - id: trunk + ref: v0.0.17 + uri: https://github.com/trunk-io/plugins +lint: + disabled: + - git-diff-check + - prettier + - prettier@2.8.7 + enabled: + - markdownlint@0.43.0 + - oxipng@9.1.4 + - yamllint@1.35.1 + - gitleaks@8.30.1 +runtimes: + enabled: + - python@3.12.5 + - go@1.23.4 + - node@22.13.0 +actions: + enabled: + - git-lfs + - trunk-announce + - trunk-check-pre-push + - trunk-fmt-pre-commit + - trunk-upgrade-available diff --git a/.warp/references/settings-schema.json b/.warp/references/settings-schema.json new file mode 100644 index 0000000..fb2c719 --- /dev/null +++ b/.warp/references/settings-schema.json @@ -0,0 +1,2723 @@ +{ + "$defs": { + "AccessibilityVerbosity": { + "description": "Verbosity level for screen reader announcements.", + "oneOf": [ + { + "const": "verbose", + "description": "Default verbosity level, includes help string.", + "type": "string" + }, + { + "const": "concise", + "description": "Concise level, only announces `value` from AccessibilityContent.", + "type": "string" + } + ] + }, + "AgentModeCodingPermissionsType": { + "description": "File read permission level for the agent.", + "oneOf": [ + { + "const": "always_ask_before_reading", + "description": "Agent Mode must ask for explicit permission for any type of file read.", + "type": "string" + }, + { + "const": "always_allow_reading", + "description": "Agent Mode can always read files without explicit consent.", + "type": "string" + }, + { + "const": "allow_reading_specific_files", + "description": "Agent Mode can only read certain files without explicit consent.\n\nThe specific filepaths are backed by the\n[`AISettings::agent_mode_coding_file_read_allowlist`] setting.", + "type": "string" + } + ] + }, + "AgentModeCommandExecutionPredicate": { + "type": "string" + }, + "AgentToolbarChipSelection": { + "description": "Agent toolbar layout configuration.", + "oneOf": [ + { + "const": "default", + "description": "Use the default toolbar layout.", + "type": "string" + }, + { + "additionalProperties": false, + "description": "Use a custom arrangement of toolbar items.", + "properties": { + "custom": { + "properties": { + "left": { + "items": { + "$ref": "#/$defs/AgentToolbarItemKind" + }, + "type": "array" + }, + "right": { + "items": { + "$ref": "#/$defs/AgentToolbarItemKind" + }, + "type": "array" + } + }, + "required": [ + "left", + "right" + ], + "type": "object" + } + }, + "required": [ + "custom" + ], + "type": "object" + } + ] + }, + "AgentToolbarItemKind": { + "description": "An item that can appear in the agent toolbar.", + "oneOf": [ + { + "enum": [ + "model_selector", + "n_l_d_toggle", + "context_window_usage", + "file_explorer", + "rich_input", + "voice_input", + "file_attach", + "share_session", + "settings", + "fast_forward_toggle" + ], + "type": "string" + }, + { + "additionalProperties": false, + "description": "A prompt context chip.", + "properties": { + "context_chip": { + "$ref": "#/$defs/ContextChipKind" + } + }, + "required": [ + "context_chip" + ], + "type": "object" + } + ] + }, + "AltScreenPaddingMode": { + "description": "How padding is applied in full-screen terminal apps.", + "oneOf": [ + { + "const": "match_blocklist", + "description": "Use the same padding as the block list.", + "type": "string" + }, + { + "additionalProperties": false, + "description": "Use a custom uniform padding value.", + "properties": { + "custom": { + "properties": { + "uniform_padding": { + "$ref": "#/$defs/Pixels" + } + }, + "required": [ + "uniform_padding" + ], + "type": "object" + } + }, + "required": [ + "custom" + ], + "type": "object" + } + ] + }, + "AppIcon": { + "description": "The app icon displayed in the dock.", + "oneOf": [ + { + "const": "default", + "description": "Default", + "type": "string" + }, + { + "const": "aurora", + "description": "Aurora", + "type": "string" + }, + { + "const": "classic1", + "description": "Classic 1", + "type": "string" + }, + { + "const": "classic2", + "description": "Classic 2", + "type": "string" + }, + { + "const": "classic3", + "description": "Classic 3", + "type": "string" + }, + { + "const": "comets", + "description": "Comets", + "type": "string" + }, + { + "const": "cow", + "description": "Cow", + "type": "string" + }, + { + "const": "glass_sky", + "description": "Glass Sky", + "type": "string" + }, + { + "const": "glitch", + "description": "Glitch", + "type": "string" + }, + { + "const": "glow", + "description": "Glow", + "type": "string" + }, + { + "const": "holographic", + "description": "Holographic", + "type": "string" + }, + { + "const": "mono", + "description": "Mono", + "type": "string" + }, + { + "const": "neon", + "description": "Neon", + "type": "string" + }, + { + "const": "original", + "description": "Original", + "type": "string" + }, + { + "const": "starburst", + "description": "Starburst", + "type": "string" + }, + { + "const": "sticker", + "description": "Sticker", + "type": "string" + }, + { + "const": "warp_one", + "description": "Warp 1", + "type": "string" + } + ] + }, + "CLIAgentToolbarChipSelection": { + "description": "CLI agent toolbar layout configuration.", + "oneOf": [ + { + "const": "default", + "description": "Use the default toolbar layout.", + "type": "string" + }, + { + "additionalProperties": false, + "description": "Use a custom arrangement of toolbar items.", + "properties": { + "custom": { + "properties": { + "left": { + "items": { + "$ref": "#/$defs/AgentToolbarItemKind" + }, + "type": "array" + }, + "right": { + "items": { + "$ref": "#/$defs/AgentToolbarItemKind" + }, + "type": "array" + } + }, + "required": [ + "left", + "right" + ], + "type": "object" + } + }, + "required": [ + "custom" + ], + "type": "object" + } + ] + }, + "ContextChipKind": { + "description": "Type of prompt context chip.", + "oneOf": [ + { + "enum": [ + "working_directory", + "username", + "hostname", + "date", + "time12", + "time24", + "virtual_environment", + "conda_environment", + "node_version", + "shell_git_branch", + "git_diff_stats", + "github_pull_request", + "kubernetes_context", + "svn_branch", + "svn_dirty_items", + "ssh", + "subshell" + ], + "type": "string" + }, + { + "additionalProperties": false, + "description": "A user-defined custom chip.", + "properties": { + "custom": { + "properties": { + "title": { + "type": "string" + } + }, + "required": [ + "title" + ], + "type": "object" + } + }, + "required": [ + "custom" + ], + "type": "object" + }, + { + "const": "agent_plan_and_todo_list", + "description": "A chip that shows the plan and todo list for the current conversation.", + "type": "string" + } + ] + }, + "CtrlTabBehavior": { + "description": "What Ctrl+Tab does.", + "enum": [ + "activate_prev_next_tab", + "cycle_most_recent_session" + ], + "type": "string" + }, + "CursorBlink": { + "description": "Whether the cursor blinks.", + "enum": [ + "enabled", + "disabled" + ], + "type": "string" + }, + "CursorDisplayType": { + "description": "Visual style of the cursor.", + "enum": [ + "bar", + "block", + "underline" + ], + "type": "string" + }, + "CustomSecretRegex": { + "description": "A custom regex pattern for detecting and redacting secrets.", + "properties": { + "name": { + "default": null, + "description": "Optional display name for this secret pattern.", + "type": [ + "string", + "null" + ] + }, + "pattern": { + "description": "The regex pattern to match secrets.", + "type": "string" + } + }, + "required": [ + "pattern" + ], + "type": "object" + }, + "CustomTheme": { + "description": "A user-provided custom theme.", + "properties": { + "name": { + "description": "The display name of the custom theme.", + "type": "string" + }, + "path": { + "description": "The file path to the custom theme definition.", + "type": "string" + } + }, + "required": [ + "name", + "path" + ], + "type": "object" + }, + "DefaultSessionMode": { + "description": "Default mode for new sessions.", + "oneOf": [ + { + "const": "terminal", + "description": "New sessions start in the terminal mode (default).", + "type": "string" + }, + { + "const": "agent", + "description": "New sessions start in agent view.", + "type": "string" + }, + { + "const": "cloud_agent", + "description": "New sessions start in cloud (ambient) agent mode.", + "type": "string" + }, + { + "const": "tab_config", + "description": "New sessions open a user-defined tab config.\nThe specific config is identified by the companion `default_tab_config_path` setting.", + "type": "string" + }, + { + "const": "docker_sandbox", + "description": "New sessions open in a local Docker sandbox.\nRequires the `LocalDockerSandbox` feature flag; falls back to `Terminal` when disabled.", + "type": "string" + } + ] + }, + "DisplayIdx": { + "description": "Which display to use when multiple monitors are connected.", + "oneOf": [ + { + "const": "primary", + "description": "The primary (main) display.", + "type": "string" + }, + { + "additionalProperties": false, + "description": "An external display, identified by index.", + "properties": { + "external": { + "type": "integer" + } + }, + "required": [ + "external" + ], + "type": "object" + } + ] + }, + "DriveSortOrder": { + "description": "Sort order for Warp Drive items.", + "oneOf": [ + { + "const": "by_timestamp", + "description": "Sort by newest revision first in main index, most recently trashed in trash index", + "type": "string" + }, + { + "const": "alphabetical_descending", + "description": "A => Z", + "type": "string" + }, + { + "const": "alphabetical_ascending", + "description": "Z => A", + "type": "string" + }, + { + "const": "by_object_type", + "description": "Sort by object type, with folders first", + "type": "string" + } + ] + }, + "Editor": { + "description": "An external code editor.", + "enum": [ + "v_s_code", + "v_s_code_insiders", + "py_charm", + "py_charm_c_e", + "intelli_j", + "intelli_j_c_e", + "c_lion", + "c_lion_c_e", + "rust_rover_preview", + "rust_rover", + "sublime4", + "sublime3", + "sublime2", + "atom", + "web_storm", + "php_storm", + "ruby_mine", + "zed", + "zed_preview", + "go_land", + "rider", + "data_spell", + "data_grip", + "android_studio", + "cursor", + "windsurf" + ], + "type": "string" + }, + "EditorChoice": { + "description": "Which editor to use when opening files.", + "oneOf": [ + { + "enum": [ + "system_default", + "warp", + "env_editor" + ], + "type": "string" + }, + { + "additionalProperties": false, + "description": "A specific external code editor.", + "properties": { + "external_editor": { + "$ref": "#/$defs/Editor" + } + }, + "required": [ + "external_editor" + ], + "type": "object" + } + ] + }, + "EditorLayout": { + "description": "Layout used when opening files in the editor.", + "enum": [ + "split_pane", + "new_tab" + ], + "type": "string" + }, + "EnforceMinimumContrast": { + "description": "When to adjust foreground color to ensure readability against the background.", + "oneOf": [ + { + "const": "never", + "description": "Never change FG color", + "type": "string" + }, + { + "const": "only_named_colors", + "description": "FG color can be changed, but only if the FG is specified with default colors", + "type": "string" + }, + { + "const": "always", + "description": "FG color is changed regardless of how FG was specified", + "type": "string" + } + ] + }, + "ExtraMetaKeys": { + "description": "Additional keys that act as the meta key.", + "properties": { + "left_alt": { + "description": "Whether the left Alt key acts as meta.", + "type": "boolean" + }, + "right_alt": { + "description": "Whether the right Alt key acts as meta.", + "type": "boolean" + } + }, + "required": [ + "left_alt", + "right_alt" + ], + "type": "object" + }, + "GraphicsBackend": { + "description": "Graphics rendering backend used for display output.", + "oneOf": [ + { + "const": "empty", + "description": "No-op backend for testing.", + "type": "string" + }, + { + "const": "dx12", + "description": "DirectX 12.", + "type": "string" + }, + { + "const": "vulkan", + "description": "Vulkan.", + "type": "string" + }, + { + "const": "gl", + "description": "OpenGL.", + "type": "string" + }, + { + "const": "metal", + "description": "Metal.", + "type": "string" + }, + { + "const": "browser_web_gpu", + "description": "WebGPU (browser).", + "type": "string" + } + ] + }, + "HeaderToolbarChipSelection": { + "description": "Configuration for the header toolbar chips in the vertical tab panel header.", + "oneOf": [ + { + "enum": [ + "default" + ], + "type": "string" + }, + { + "additionalProperties": false, + "properties": { + "custom": { + "properties": { + "left": { + "items": { + "$ref": "#/$defs/HeaderToolbarItemKind" + }, + "type": "array" + }, + "right": { + "items": { + "$ref": "#/$defs/HeaderToolbarItemKind" + }, + "type": "array" + } + }, + "required": [ + "left", + "right" + ], + "type": "object" + } + }, + "required": [ + "custom" + ], + "type": "object" + } + ] + }, + "HeaderToolbarItemKind": { + "description": "A configurable item in the vertical tabs header toolbar.\n\nEach variant represents a panel toggle button that can be placed on either\nthe left or right side of the toolbar. The side determines which side of the\nmain content area the panel opens on.", + "enum": [ + "tabs_panel", + "tools_panel", + "agent_management", + "code_review", + "notifications_mailbox" + ], + "type": "string" + }, + "InputBoxType": { + "description": "Terminal input style.", + "oneOf": [ + { + "const": "universal", + "description": "AI-first input", + "type": "string" + }, + { + "const": "classic", + "description": "Terminal-first input", + "type": "string" + } + ] + }, + "InputMode": { + "description": "Direction that blocks flow in the terminal viewport.", + "oneOf": [ + { + "const": "pinned_to_bottom", + "description": "The most recent blocks are at the bottom of the screen and new blocks\nare added at the bottom as the blocklist grows", + "type": "string" + }, + { + "const": "pinned_to_top", + "description": "The most recent blocks are at the top of the screen and new blocks\nare added at the top as the blocklist grows", + "type": "string" + }, + { + "const": "waterfall", + "description": "The input starts at the top and gets pushed down by commands above it.", + "type": "string" + } + ] + }, + "Keystroke": { + "type": "string" + }, + "NewSessionShell": { + "description": "Shell to use when opening new sessions.", + "oneOf": [ + { + "const": "system_default", + "description": "Use the operating system's default shell.", + "type": "string" + }, + { + "additionalProperties": false, + "description": "A shell executable path.", + "properties": { + "executable": { + "type": "string" + } + }, + "required": [ + "executable" + ], + "type": "object" + }, + { + "additionalProperties": false, + "description": "An MSYS2 shell environment.", + "properties": { + "m_s_y_s2": { + "type": "string" + } + }, + "required": [ + "m_s_y_s2" + ], + "type": "object" + }, + { + "additionalProperties": false, + "description": "A Windows Subsystem for Linux distribution.", + "properties": { + "w_s_l": { + "type": "string" + } + }, + "required": [ + "w_s_l" + ], + "type": "object" + }, + { + "additionalProperties": false, + "description": "A custom shell command.", + "properties": { + "custom": { + "type": "string" + } + }, + "required": [ + "custom" + ], + "type": "object" + } + ] + }, + "NewTabPlacement": { + "description": "Where new tabs are placed in the tab bar.", + "enum": [ + "after_current_tab", + "after_all_tabs" + ], + "type": "string" + }, + "NotificationsMode": { + "description": "Whether the user has enabled or disabled notifications.", + "oneOf": [ + { + "const": "unset", + "description": "Notifications have not been configured yet.", + "type": "string" + }, + { + "const": "dismissed", + "description": "The notifications banner has been dismissed.", + "type": "string" + }, + { + "const": "enabled", + "description": "Notifications are enabled.", + "type": "string" + }, + { + "const": "disabled", + "description": "Notifications are disabled.", + "type": "string" + } + ] + }, + "NotificationsSettings": { + "description": "Notification preferences for terminal events.", + "properties": { + "is_agent_task_completed_enabled": { + "default": true, + "description": "Whether to notify when an agent task completes.", + "type": "boolean" + }, + "is_long_running_enabled": { + "default": true, + "description": "Whether to notify when a long-running command completes.", + "type": "boolean" + }, + "is_needs_attention_enabled": { + "default": true, + "description": "Whether to notify when a session needs attention.", + "type": "boolean" + }, + "is_password_prompt_enabled": { + "default": true, + "description": "Whether to notify when a password prompt is detected.", + "type": "boolean" + }, + "long_running_threshold": { + "default": { + "nanos": 0, + "secs": 30 + }, + "description": "Threshold in seconds for long-running command notifications.", + "type": "integer" + }, + "mode": { + "$ref": "#/$defs/NotificationsMode", + "default": "Unset", + "description": "Whether notifications are enabled, disabled, or not yet configured." + }, + "play_notification_sound": { + "default": true, + "description": "Whether to play a sound with notifications.", + "type": "boolean" + } + }, + "type": "object" + }, + "OpenConversationPreference": { + "description": "How to open agent conversations.", + "enum": [ + "new_tab", + "split_pane" + ], + "type": "string" + }, + "Pixels": { + "description": "A value in pixels.", + "type": "number" + }, + "QuakeModePinPosition": { + "description": "Screen edge to pin the hotkey window to.", + "enum": [ + "top", + "bottom", + "left", + "right" + ], + "type": "string" + }, + "QuakeModeSettings": { + "description": "Configuration for the hotkey window.", + "properties": { + "active_pin_position": { + "$ref": "#/$defs/QuakeModePinPosition", + "description": "Screen edge where the hotkey window is pinned." + }, + "hide_window_when_unfocused": { + "description": "Whether to hide the hotkey window when it loses focus.", + "type": "boolean" + }, + "keybinding": { + "anyOf": [ + { + "$ref": "#/$defs/Keystroke" + }, + { + "type": "null" + } + ], + "description": "Keyboard shortcut to toggle the hotkey window. Format: modifiers (cmd, ctrl, alt, shift, meta) and a key joined by '-', e.g. \"cmd-shift-a\" or \"alt-enter\". Bindings are case-sensitive: when shift is present, the key must be its shifted form (e.g., \"ctrl-shift-E\", not \"ctrl-shift-e\")." + }, + "pin_position_to_size_percentages": { + "additionalProperties": { + "$ref": "#/$defs/SizePercentages" + }, + "description": "Window size percentages for each pin position.", + "type": "object" + }, + "pin_screen": { + "anyOf": [ + { + "$ref": "#/$defs/DisplayIdx" + }, + { + "type": "null" + } + ], + "description": "Display to pin the hotkey window to." + } + }, + "required": [ + "active_pin_position", + "pin_position_to_size_percentages", + "hide_window_when_unfocused" + ], + "type": "object" + }, + "SecretDisplayMode": { + "description": "How detected secrets are visually displayed.", + "oneOf": [ + { + "const": "asterisks", + "description": "Fully obscure secrets with asterisks", + "type": "string" + }, + { + "const": "strikethrough", + "description": "Show secrets with gray color and strikethrough styling", + "type": "string" + }, + { + "const": "always_show", + "description": "Show secrets normally with no visual treatment (but are still detected/redacted)", + "type": "string" + } + ] + }, + "SelectedSystemThemes": { + "description": "Themes to use when following the system light/dark mode.", + "properties": { + "dark": { + "$ref": "#/$defs/ThemeKind", + "description": "The theme to use in dark mode." + }, + "light": { + "$ref": "#/$defs/ThemeKind", + "description": "The theme to use in light mode." + } + }, + "required": [ + "light", + "dark" + ], + "type": "object" + }, + "SizePercentages": { + "description": "Window size as width and height percentages of the screen.", + "properties": { + "height": { + "description": "Height as a percentage of screen height (0–100).", + "type": "integer" + }, + "width": { + "description": "Width as a percentage of screen width (0–100).", + "type": "integer" + } + }, + "required": [ + "width", + "height" + ], + "type": "object" + }, + "SpacingMode": { + "description": "Terminal block spacing.", + "oneOf": [ + { + "const": "normal", + "description": "Normal", + "type": "string" + }, + { + "const": "compact", + "description": "Compact", + "type": "string" + } + ] + }, + "SshExtensionInstallMode": { + "description": "Controls SSH extension installation behavior.", + "oneOf": [ + { + "const": "always_ask", + "description": "Always prompt the user before installing (default).", + "type": "string" + }, + { + "const": "always_install", + "description": "Automatically install and connect without prompting.", + "type": "string" + }, + { + "const": "never_install", + "description": "Never install; fall back to legacy warpification.", + "type": "string" + } + ] + }, + "StartupShell": { + "description": "Shell to start terminal sessions with. Use null for the system default, or one of \"bash\", \"zsh\", \"fish\", \"pwsh\", or a custom shell command/path.", + "type": [ + "string", + "null" + ] + }, + "TabCloseButtonPosition": { + "description": "Position of the close button on tabs.", + "enum": [ + "right", + "left" + ], + "type": "string" + }, + "ThemeKind": { + "description": "The color theme.", + "oneOf": [ + { + "const": "adeberry", + "description": "Adeberry", + "type": "string" + }, + { + "const": "phenomenon", + "description": "Phenomenon", + "type": "string" + }, + { + "const": "dark", + "description": "Dark", + "type": "string" + }, + { + "const": "dracula", + "description": "Dracula", + "type": "string" + }, + { + "const": "fancy_dracula", + "description": "Fancy Dracula", + "type": "string" + }, + { + "const": "cyber_wave", + "description": "Cyber Wave", + "type": "string" + }, + { + "const": "solar_flare", + "description": "Solar Flare", + "type": "string" + }, + { + "const": "solarized_dark", + "description": "Solarized Dark", + "type": "string" + }, + { + "const": "willow_dream", + "description": "Willow Dream", + "type": "string" + }, + { + "const": "light", + "description": "Light", + "type": "string" + }, + { + "const": "dark_city", + "description": "Dark City", + "type": "string" + }, + { + "const": "gruvbox_dark", + "description": "Gruvbox Dark", + "type": "string" + }, + { + "const": "red_rock", + "description": "Red Rock", + "type": "string" + }, + { + "const": "jelly_fish", + "description": "Jellyfish", + "type": "string" + }, + { + "const": "leafy", + "description": "Leafy", + "type": "string" + }, + { + "const": "koi", + "description": "Koi", + "type": "string" + }, + { + "const": "solarized_light", + "description": "Solarized Light", + "type": "string" + }, + { + "const": "snowy", + "description": "Snowy", + "type": "string" + }, + { + "const": "gruvbox_light", + "description": "Gruvbox Light", + "type": "string" + }, + { + "const": "pink_city", + "description": "Pink City", + "type": "string" + }, + { + "const": "marble", + "description": "Marble", + "type": "string" + }, + { + "additionalProperties": false, + "description": "A user-provided custom theme loaded from a file.", + "properties": { + "custom": { + "$ref": "#/$defs/CustomTheme" + } + }, + "required": [ + "custom" + ], + "type": "object" + }, + { + "additionalProperties": false, + "description": "A custom theme using the Base16 color scheme format.", + "properties": { + "custom_base16": { + "$ref": "#/$defs/CustomTheme" + } + }, + "required": [ + "custom_base16" + ], + "type": "object" + } + ] + }, + "ThinStrokes": { + "description": "When to render text with thinner strokes for a lighter appearance.", + "oneOf": [ + { + "const": "never", + "description": "Never render glyphs using thin strokes.", + "type": "string" + }, + { + "const": "on_low_dpi_displays", + "description": "Render glyphs using thin strokes when rendering on a low-DPI display.", + "type": "string" + }, + { + "const": "on_high_dpi_displays", + "description": "Render glyphs using thin strokes when rendering on a high-DPI display.", + "type": "string" + }, + { + "const": "always", + "description": "Always render glyphs using thin strokes.", + "type": "string" + } + ] + }, + "ThinkingDisplayMode": { + "description": "Controls how agent thinking is displayed after streaming.", + "oneOf": [ + { + "const": "show_and_collapse", + "description": "Show reasoning blocks while streaming, then collapse them when complete (default).", + "type": "string" + }, + { + "const": "always_show", + "description": "Always keep reasoning blocks expanded, even after streaming finishes.", + "type": "string" + }, + { + "const": "never_show", + "description": "Never show reasoning blocks.", + "type": "string" + } + ] + }, + "ToolbarCommandMap": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "UserNativePreference": { + "description": "Preference for using the native desktop app or the web app.", + "enum": [ + "not_selected", + "web", + "desktop" + ], + "type": "string" + }, + "VerticalTabsCompactSubtitle": { + "description": "Subtitle shown on compact vertical tabs.", + "enum": [ + "branch", + "working_directory", + "command" + ], + "type": "string" + }, + "VerticalTabsDisplayGranularity": { + "description": "Granularity of rows displayed in the vertical tabs panel.", + "enum": [ + "panes", + "tabs" + ], + "type": "string" + }, + "VerticalTabsPrimaryInfo": { + "description": "Primary information displayed on vertical tabs.", + "enum": [ + "command", + "working_directory", + "branch" + ], + "type": "string" + }, + "VerticalTabsTabItemMode": { + "description": "Tab item display mode in vertical tabs.", + "enum": [ + "focused_session", + "summary" + ], + "type": "string" + }, + "VerticalTabsViewMode": { + "description": "Display mode for the vertical tab bar.", + "enum": [ + "compact", + "expanded" + ], + "type": "string" + }, + "VoiceInputToggleKey": { + "description": "Physical key used to toggle voice input.", + "oneOf": [ + { + "const": "none", + "description": "No toggle key assigned.", + "type": "string" + }, + { + "const": "fn", + "description": "Fn key.", + "type": "string" + }, + { + "const": "alt_left", + "description": "Alt or Option key (left side).", + "type": "string" + }, + { + "const": "alt_right", + "description": "Alt or Option key (right side).", + "type": "string" + }, + { + "const": "control_left", + "description": "Control key (left side).", + "type": "string" + }, + { + "const": "control_right", + "description": "Control key (right side).", + "type": "string" + }, + { + "const": "super_left", + "description": "Super, Windows, or Command key (left side).", + "type": "string" + }, + { + "const": "super_right", + "description": "Super, Windows, or Command key (right side).", + "type": "string" + }, + { + "const": "shift_left", + "description": "Shift key (left side).", + "type": "string" + }, + { + "const": "shift_right", + "description": "Shift key (right side).", + "type": "string" + } + ] + }, + "Weight": { + "description": "Font weight for terminal text.", + "enum": [ + "thin", + "extra_light", + "light", + "normal", + "medium", + "semibold", + "bold", + "extra_bold", + "black" + ], + "type": "string" + }, + "WorkingDirectoryConfig": { + "description": "Configuration for the initial working directory of new sessions.", + "properties": { + "advanced_mode": { + "description": "Whether to use separate settings per session source.", + "type": "boolean" + }, + "global": { + "$ref": "#/$defs/WorkingDirectoryPerSourceConfig", + "description": "Default working directory settings used when advanced mode is off." + }, + "new_tab": { + "$ref": "#/$defs/WorkingDirectoryPerSourceConfig", + "description": "Working directory settings for new tab sessions." + }, + "new_window": { + "$ref": "#/$defs/WorkingDirectoryPerSourceConfig", + "description": "Working directory settings for new window sessions." + }, + "split_pane": { + "$ref": "#/$defs/WorkingDirectoryPerSourceConfig", + "description": "Working directory settings for split pane sessions." + } + }, + "required": [ + "advanced_mode", + "global", + "split_pane", + "new_tab", + "new_window" + ], + "type": "object" + }, + "WorkingDirectoryMode": { + "description": "Where new sessions start.", + "oneOf": [ + { + "const": "home_dir", + "description": "Start a new session in the user's home directory.", + "type": "string" + }, + { + "const": "previous_dir", + "description": "Start a new session in the same directory as the previous session.", + "type": "string" + }, + { + "const": "custom_dir", + "description": "Start a new session in a specific directory.", + "type": "string" + } + ] + }, + "WorkingDirectoryPerSourceConfig": { + "description": "Working directory settings for a specific session source.", + "properties": { + "custom_dir": { + "description": "Custom directory path, used when mode is CustomDir.", + "type": "string" + }, + "mode": { + "$ref": "#/$defs/WorkingDirectoryMode", + "description": "How the working directory is determined." + } + }, + "required": [ + "mode", + "custom_dir" + ], + "type": "object" + }, + "WorkspaceDecorationVisibility": { + "description": "When workspace decorations such as the tab bar are visible.", + "oneOf": [ + { + "const": "always_show", + "description": "Always show workspace decorations.", + "type": "string" + }, + { + "const": "hide_fullscreen", + "description": "Hide workspace decorations if fullscreen.", + "type": "string" + }, + { + "const": "on_hover", + "description": "Only show workspace decorations on hover.", + "type": "string" + } + ] + } + }, + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "JSON Schema for Warp settings (stable channel, 183 settings)", + "properties": { + "accessibility": { + "properties": { + "accessibility_verbosity": { + "$ref": "#/$defs/AccessibilityVerbosity", + "default": "verbose", + "description": "The verbosity level for screen reader announcements." + } + }, + "type": "object" + }, + "account": { + "properties": { + "is_settings_sync_enabled": { + "default": false, + "description": "Whether settings are synced across devices via the cloud.", + "type": "boolean" + } + }, + "type": "object" + }, + "agents": { + "properties": { + "cloud_conversation_storage_enabled": { + "default": true, + "description": "Whether conversations are stored in the cloud.", + "type": "boolean" + }, + "knowledge": { + "properties": { + "rules_enabled": { + "default": true, + "description": "Whether the agent uses your saved rules during requests.", + "type": "boolean" + }, + "warp_drive_context_enabled": { + "default": true, + "description": "Whether Warp Drive context is included in AI requests.", + "type": "boolean" + } + }, + "type": "object" + }, + "mcp_servers": { + "properties": { + "file_based_mcp_enabled": { + "default": false, + "description": "Whether third-party file-based MCP servers are automatically detected.", + "type": "boolean" + } + }, + "type": "object" + }, + "oz": { + "properties": { + "active_ai": { + "properties": { + "git_operations_autogen_enabled": { + "default": true, + "description": "Controls whether AI auto-generates commit messages and PR title/body in the code review dialogs.", + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "profiles": { + "properties": { + "agent_mode_coding_file_read_allowlist": { + "default": [], + "description": "File paths the agent can read without asking for permission.", + "items": { + "type": "string" + }, + "type": "array" + }, + "agent_mode_coding_permissions": { + "$ref": "#/$defs/AgentModeCodingPermissionsType", + "default": "always_ask_before_reading", + "description": "The file read permission level for the agent." + }, + "agent_mode_command_execution_allowlist": { + "default": [ + "cat(\\s.*)?", + "echo(\\s.*)?", + "find .*", + "grep(\\s.*)?", + "ls(\\s.*)?", + "which .*" + ], + "description": "Commands that the agent can execute without explicit permission.", + "items": { + "$ref": "#/$defs/AgentModeCommandExecutionPredicate" + }, + "type": "array" + }, + "agent_mode_command_execution_denylist": { + "default": [ + "bash(\\s.*)?", + "fish(\\s.*)?", + "pwsh(\\s.*)?", + "sh(\\s.*)?", + "zsh(\\s.*)?", + "curl(\\s.*)?", + "eval(\\s.*)?", + "exec(\\s.*)?", + "source(\\s.*)?", + "wget(\\s.*)?", + "dig(\\s.*)?", + "nslookup(\\s.*)?", + "host(\\s.*)?", + "ssh(\\s.*)?", + "scp(\\s.*)?", + "rsync(\\s.*)?", + "telnet(\\s.*)?", + "rm(\\s.*)?" + ], + "description": "Commands that the agent must always ask before executing.", + "items": { + "$ref": "#/$defs/AgentModeCommandExecutionPredicate" + }, + "type": "array" + }, + "agent_mode_execute_readonly_commands": { + "default": false, + "description": "Whether the agent can auto-execute read-only commands without asking.", + "type": "boolean" + } + }, + "type": "object" + }, + "third_party": { + "properties": { + "auto_dismiss_composer_after_submit": { + "default": false, + "description": "Whether CLI agent Rich Input automatically closes after the user submits a prompt.", + "type": "boolean" + }, + "auto_open_composer_on_cli_agent_start": { + "default": false, + "description": "Whether CLI agent Rich Input automatically opens when a CLI agent session starts.", + "type": "boolean" + }, + "auto_toggle_composer": { + "default": true, + "description": "Whether CLI agent Rich Input automatically closes and reopens based on the agent's blocked state.", + "type": "boolean" + }, + "cli_agent_toolbar_chip_selection_setting": { + "$ref": "#/$defs/CLIAgentToolbarChipSelection", + "default": "default", + "description": "Controls the layout of context chips in the CLI Agent toolbar." + }, + "cli_agent_toolbar_enabled_commands": { + "$ref": "#/$defs/ToolbarCommandMap", + "default": {}, + "description": "Maps custom toolbar command patterns to specific CLI agents." + }, + "should_render_cli_agent_toolbar": { + "default": true, + "description": "Whether to show the CLI agent footer for coding agent commands.", + "type": "boolean" + } + }, + "type": "object" + }, + "voice": { + "properties": { + "voice_input_enabled": { + "default": true, + "description": "Controls whether voice input is enabled for AI interactions.", + "type": "boolean" + }, + "voice_input_toggle_key": { + "$ref": "#/$defs/VoiceInputToggleKey", + "default": "none", + "description": "The key used to toggle voice input." + } + }, + "type": "object" + }, + "warp_agent": { + "properties": { + "active_ai": { + "properties": { + "agent_mode_query_suggestions_enabled": { + "default": true, + "description": "Controls whether prompt suggestions are shown in agent mode.", + "type": "boolean" + }, + "code_suggestions_enabled": { + "default": true, + "description": "Controls whether AI code suggestions are enabled.", + "type": "boolean" + }, + "enabled": { + "default": true, + "description": "Controls whether proactive AI features like suggestions are enabled.", + "type": "boolean" + }, + "intelligent_autosuggestions_enabled": { + "default": true, + "description": "Controls whether AI-powered intelligent autosuggestions are enabled.", + "type": "boolean" + }, + "shared_block_title_generation_enabled": { + "default": true, + "description": "Controls whether titles are auto-generated when sharing blocks.", + "type": "boolean" + } + }, + "type": "object" + }, + "input": { + "properties": { + "agent_toolbar_chip_selection_setting": { + "$ref": "#/$defs/AgentToolbarChipSelection", + "default": "default", + "description": "Controls the layout of context chips in the Agent Mode toolbar." + }, + "ai_auto_detection_enabled": { + "default": true, + "description": "Controls whether AI automatically detects natural language input.", + "type": "boolean" + }, + "ai_command_denylist": { + "default": "", + "description": "Commands to exclude from AI natural language autodetection.", + "type": "string" + }, + "include_agent_commands_in_history": { + "default": false, + "description": "Whether agent-executed commands are included in command history.", + "type": "boolean" + }, + "nld_in_terminal_enabled": { + "default": false, + "description": "Controls whether natural language detection is enabled in the terminal input.", + "type": "boolean" + }, + "show_agent_tips": { + "default": true, + "description": "Whether agent tips are displayed in the input.", + "type": "boolean" + }, + "show_model_selectors_in_prompt": { + "default": true, + "description": "Whether to show AI model selectors in the input prompt.", + "type": "boolean" + } + }, + "type": "object" + }, + "is_any_ai_enabled": { + "default": true, + "description": "Controls whether all AI features are enabled.", + "type": "boolean" + }, + "other": { + "properties": { + "cloud_agent_computer_use_enabled": { + "default": false, + "description": "Whether computer use is enabled for cloud agent conversations.", + "type": "boolean" + }, + "open_conversation_layout_preference": { + "$ref": "#/$defs/OpenConversationPreference", + "default": "new_tab", + "description": "Whether to open agent conversations in a new tab or a split pane." + }, + "should_render_use_agent_toolbar_for_user_commands": { + "default": true, + "description": "Whether to show the \"Use Agent\" footer for terminal commands.", + "type": "boolean" + }, + "should_show_oz_updates_in_zero_state": { + "default": true, + "description": "Whether the \"What's new\" section is shown in the agent view.", + "type": "boolean" + }, + "show_agent_notifications": { + "default": true, + "description": "Whether agent notifications are shown.", + "type": "boolean" + }, + "show_conversation_history": { + "default": true, + "description": "Whether conversation history appears in the tools panel.", + "type": "boolean" + }, + "thinking_display_mode": { + "$ref": "#/$defs/ThinkingDisplayMode", + "default": "show_and_collapse", + "description": "Controls how agent thinking traces are displayed after streaming." + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "appearance": { + "properties": { + "blocks": { + "properties": { + "should_show_bootstrap_block": { + "default": false, + "description": "Whether the bootstrap block is visible in the terminal.", + "type": "boolean" + }, + "should_show_in_band_command_blocks": { + "default": false, + "description": "Whether in-band command blocks are visible in the terminal.", + "type": "boolean" + }, + "should_show_ssh_block": { + "default": false, + "description": "Whether the SSH connection block is visible in the terminal.", + "type": "boolean" + }, + "show_block_dividers": { + "default": true, + "description": "Whether to show dividers between terminal blocks.", + "type": "boolean" + }, + "show_jump_to_bottom_of_block_button": { + "default": true, + "description": "Whether to show the jump-to-bottom button in long command output.", + "type": "boolean" + } + }, + "type": "object" + }, + "cursor": { + "properties": { + "cursor_blink": { + "$ref": "#/$defs/CursorBlink", + "default": "enabled", + "description": "Whether the cursor blinks." + }, + "cursor_display_type": { + "$ref": "#/$defs/CursorDisplayType", + "default": "bar", + "description": "The visual style of the cursor." + } + }, + "type": "object" + }, + "full_screen_apps": { + "properties": { + "alt_screen_padding": { + "$ref": "#/$defs/AltScreenPaddingMode", + "default": { + "custom": { + "uniform_padding": 0.0 + } + }, + "description": "Controls padding around full-screen terminal applications." + } + }, + "type": "object" + }, + "icon": { + "properties": { + "app_icon": { + "$ref": "#/$defs/AppIcon", + "default": "default", + "description": "The app icon displayed in the dock." + } + }, + "type": "object" + }, + "input": { + "properties": { + "input_mode": { + "$ref": "#/$defs/InputMode", + "default": "pinned_to_bottom", + "description": "The position of the terminal input." + } + }, + "type": "object" + }, + "panes": { + "properties": { + "focus_pane_on_hover": { + "default": false, + "description": "Whether panes are focused when hovered over.", + "type": "boolean" + }, + "should_dim_inactive_panes": { + "default": false, + "description": "Whether inactive panes are visually dimmed.", + "type": "boolean" + } + }, + "type": "object" + }, + "spacing": { + "$ref": "#/$defs/SpacingMode", + "default": "normal", + "description": "Controls the spacing between terminal blocks." + }, + "tabs": { + "properties": { + "header_toolbar_chip_selection": { + "$ref": "#/$defs/HeaderToolbarChipSelection", + "default": "default", + "description": "Configuration for the header toolbar chips in the vertical tab panel header." + }, + "preserve_active_tab_color": { + "default": false, + "description": "Whether to preserve the active tab's color when switching tabs.", + "type": "boolean" + }, + "show_indicators_button": { + "default": true, + "description": "Whether to show activity indicators on tabs.", + "type": "boolean" + }, + "tab_close_button_position": { + "$ref": "#/$defs/TabCloseButtonPosition", + "default": "right", + "description": "Position of the close button on tabs." + }, + "workspace_decoration_visibility": { + "$ref": "#/$defs/WorkspaceDecorationVisibility", + "default": "hide_fullscreen", + "description": "When workspace decorations such as the tab bar are visible." + } + }, + "type": "object" + }, + "text": { + "properties": { + "ai_font_name": { + "default": "Hack", + "description": "The font used for AI-generated content.", + "type": "string" + }, + "enforce_minimum_contrast": { + "$ref": "#/$defs/EnforceMinimumContrast", + "default": "only_named_colors", + "description": "Whether to enforce minimum contrast for text readability." + }, + "font_name": { + "default": "Hack", + "description": "The monospace font used in the terminal.", + "type": "string" + }, + "font_size": { + "default": 13.0, + "description": "The size of the monospace font in the terminal.", + "type": "number" + }, + "font_weight": { + "$ref": "#/$defs/Weight", + "default": "normal", + "description": "The weight of the monospace font in the terminal." + }, + "ligature_rendering_enabled": { + "default": false, + "description": "Whether to render font ligatures in the terminal.", + "type": "boolean" + }, + "line_height_ratio": { + "default": 1.2000000476837158, + "description": "The line height ratio for terminal text.", + "type": "number" + }, + "match_ai_font": { + "default": false, + "description": "Whether the AI font automatically matches the terminal font.", + "type": "boolean" + }, + "match_notebook_to_monospace_font_size": { + "default": true, + "description": "Whether the notebook font size matches the terminal font size.", + "type": "boolean" + }, + "notebook_font_size": { + "default": 14.0, + "description": "The font size used in notebooks.", + "type": "number" + }, + "use_thin_strokes": { + "$ref": "#/$defs/ThinStrokes", + "default": "on_high_dpi_displays", + "description": "Whether to use thin font strokes on macOS." + } + }, + "type": "object" + }, + "themes": { + "properties": { + "selected_system_themes": { + "$ref": "#/$defs/SelectedSystemThemes", + "default": { + "dark": "dark", + "light": "light" + }, + "description": "The themes to use for system light and dark modes." + }, + "system_theme": { + "default": false, + "description": "Whether to match the system light/dark theme.", + "type": "boolean" + }, + "theme": { + "$ref": "#/$defs/ThemeKind", + "default": "dark", + "description": "The color theme." + } + }, + "type": "object" + }, + "vertical_tabs": { + "properties": { + "compact_subtitle": { + "$ref": "#/$defs/VerticalTabsCompactSubtitle", + "default": "branch", + "description": "Subtitle shown on compact vertical tabs." + }, + "display_granularity": { + "$ref": "#/$defs/VerticalTabsDisplayGranularity", + "default": "panes", + "description": "Granularity of rows displayed in the vertical tabs panel." + }, + "enabled": { + "default": false, + "description": "Whether to display tabs vertically instead of horizontally.", + "type": "boolean" + }, + "primary_info": { + "$ref": "#/$defs/VerticalTabsPrimaryInfo", + "default": "command", + "description": "The primary information displayed on vertical tabs." + }, + "show_details_on_hover": { + "default": true, + "description": "Whether to show a details sidecar when hovering over a vertical tab.", + "type": "boolean" + }, + "show_diff_stats": { + "default": true, + "description": "Whether to show diff stats on vertical tabs.", + "type": "boolean" + }, + "show_pr_link": { + "default": true, + "description": "Whether to show PR links on vertical tabs.", + "type": "boolean" + }, + "tab_item_mode": { + "$ref": "#/$defs/VerticalTabsTabItemMode", + "default": "focused_session", + "description": "Tab item display mode in vertical tabs." + }, + "use_latest_prompt_as_title": { + "default": false, + "description": "Whether vertical tab names for agent conversations use the latest user prompt.", + "type": "boolean" + }, + "view_mode": { + "$ref": "#/$defs/VerticalTabsViewMode", + "default": "compact", + "description": "Display mode for the vertical tab bar." + } + }, + "type": "object" + }, + "window": { + "properties": { + "left_panel_visibility_across_tabs": { + "default": true, + "description": "Whether the left panel visibility is shared across all tabs.", + "type": "boolean" + }, + "new_windows_num_columns": { + "default": 80, + "description": "The number of columns for new windows when using a custom size.", + "type": "integer" + }, + "new_windows_num_rows": { + "default": 40, + "description": "The number of rows for new windows when using a custom size.", + "type": "integer" + }, + "open_windows_at_custom_size": { + "default": false, + "description": "Whether to open new windows at a custom size instead of the default.", + "type": "boolean" + }, + "override_blur": { + "default": 1, + "description": "The blur radius applied to the window background.", + "type": "integer" + }, + "override_blur_texture": { + "default": false, + "description": "Whether to apply a blur texture to the window background.", + "type": "boolean" + }, + "override_opacity": { + "default": 100, + "description": "The opacity of the window background, from 1 to 100 percent.", + "type": "integer" + }, + "zoom_level": { + "default": 100, + "description": "The zoom level for the window, as a percentage.", + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "cloud_platform": { + "properties": { + "third_party_api_keys": { + "properties": { + "aws_bedrock_auth_refresh_command": { + "default": "aws login", + "description": "The command to run to refresh AWS credentials for Bedrock.", + "type": "string" + }, + "aws_bedrock_auto_login": { + "default": false, + "description": "Whether to automatically run the AWS login command when Bedrock credentials expire.", + "type": "boolean" + }, + "aws_bedrock_credentials_enabled": { + "default": false, + "description": "Whether Warp should use your local AWS credentials for Bedrock-enabled requests.", + "type": "boolean" + }, + "aws_bedrock_profile": { + "default": "default", + "description": "The AWS profile name to use for Bedrock credentials.", + "type": "string" + }, + "can_use_warp_credits_with_byok": { + "default": false, + "description": "Whether Warp credits can be used even when providing your own API key.", + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "code": { + "properties": { + "editor": { + "properties": { + "auto_open_code_review_pane_on_first_agent_change": { + "default": false, + "description": "Whether to automatically open the code review pane when the agent makes its first change.", + "type": "boolean" + }, + "open_code_panels_file_editor": { + "$ref": "#/$defs/EditorChoice", + "default": "warp", + "description": "The editor used to open files from code panels." + }, + "open_file_editor": { + "$ref": "#/$defs/EditorChoice", + "default": "system_default", + "description": "The editor used to open files." + }, + "open_file_layout": { + "$ref": "#/$defs/EditorLayout", + "default": "split_pane", + "description": "The layout used when opening files in the editor." + }, + "prefer_markdown_viewer": { + "default": true, + "description": "Whether to use the Markdown viewer when opening Markdown files.", + "type": "boolean" + }, + "prefer_tabbed_editor_view": { + "default": true, + "description": "Whether to prefer opening files in a tabbed editor view.", + "type": "boolean" + }, + "show_code_review_button": { + "default": true, + "description": "Whether to show the code review button on tabs.", + "type": "boolean" + }, + "show_code_review_diff_stats": { + "default": true, + "description": "Whether to show lines added/removed counts on the code review button.", + "type": "boolean" + }, + "show_global_search": { + "default": true, + "description": "Whether global file search is shown in the tools panel.", + "type": "boolean" + }, + "show_project_explorer": { + "default": true, + "description": "Whether the project explorer is shown in the tools panel.", + "type": "boolean" + }, + "use_warp_as_default_editor": { + "default": false, + "description": "Whether Warp is used as the default code editor.", + "type": "boolean" + } + }, + "type": "object" + }, + "indexing": { + "properties": { + "agent_mode_codebase_context": { + "default": true, + "description": "Whether codebase context is provided to the AI agent.", + "type": "boolean" + }, + "agent_mode_codebase_context_auto_indexing": { + "default": false, + "description": "Whether automatic codebase indexing is enabled.", + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "general": { + "properties": { + "default_session_mode": { + "$ref": "#/$defs/DefaultSessionMode", + "default": "terminal", + "description": "The default mode for new terminal sessions." + }, + "default_tab_config_path": { + "default": "", + "type": "string" + }, + "link_tooltip": { + "default": true, + "description": "Whether to show a tooltip when hovering over links.", + "type": "boolean" + }, + "login_item": { + "default": true, + "description": "Whether to launch Warp automatically when you log in.", + "type": "boolean" + }, + "mouse_scroll_multiplier": { + "default": 3.0, + "description": "The scroll speed multiplier for mouse scroll events.", + "type": "number" + }, + "new_tab_placement": { + "$ref": "#/$defs/NewTabPlacement", + "default": "after_current_tab", + "description": "Where new tabs are placed in the tab bar." + }, + "quit_on_last_window_closed": { + "default": false, + "description": "Whether to quit Warp when the last window is closed.", + "type": "boolean" + }, + "restore_session": { + "default": true, + "description": "Whether to restore the previous session when Warp starts up.", + "type": "boolean" + }, + "should_confirm_close_session": { + "default": true, + "description": "Whether to show a confirmation dialog when closing a session.", + "type": "boolean" + }, + "show_changelog_after_update": { + "default": true, + "description": "Whether the changelog is shown after an update.", + "type": "boolean" + }, + "show_warning_before_quitting": { + "default": true, + "description": "Whether to show a warning dialog before quitting Warp.", + "type": "boolean" + }, + "snackbar_enabled": { + "default": true, + "description": "Whether to show snackbar notifications.", + "type": "boolean" + }, + "undo_close": { + "properties": { + "enabled": { + "default": true, + "description": "Whether the undo close feature is enabled.", + "type": "boolean" + }, + "grace_period": { + "default": 60, + "description": "How long after closing a tab you can still undo the close.", + "type": "integer" + } + }, + "type": "object" + }, + "user_native_preference": { + "$ref": "#/$defs/UserNativePreference", + "default": "not_selected", + "description": "Whether to prefer the native desktop app or the web app." + } + }, + "type": "object" + }, + "global_hotkey": { + "properties": { + "dedicated_window": { + "properties": { + "enabled": { + "default": false, + "description": "Whether the dedicated hotkey window is enabled. Mutually exclusive with `global_hotkey.toggle_all_windows.enabled`; only one should be true at a time.", + "type": "boolean" + }, + "settings": { + "$ref": "#/$defs/QuakeModeSettings", + "default": { + "active_pin_position": "top", + "hide_window_when_unfocused": true, + "keybinding": null, + "pin_position_to_size_percentages": { + "bottom": { + "height": 30, + "width": 100 + }, + "left": { + "height": 100, + "width": 40 + }, + "right": { + "height": 100, + "width": 40 + }, + "top": { + "height": 30, + "width": 100 + } + }, + "pin_screen": null + }, + "description": "Configuration options for Quake Mode window behavior." + } + }, + "type": "object" + }, + "toggle_all_windows": { + "properties": { + "enabled": { + "default": false, + "description": "Whether the hotkey that toggles visibility of all windows is enabled. Mutually exclusive with `global_hotkey.dedicated_window.enabled`; only one should be true at a time.", + "type": "boolean" + }, + "keybinding": { + "anyOf": [ + { + "$ref": "#/$defs/Keystroke" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The keybinding used for the global activation hotkey. Format: modifiers (cmd, ctrl, alt, shift, meta) and a key joined by '-', e.g. \"cmd-shift-a\" or \"alt-enter\". Bindings are case-sensitive: when shift is present, the key must be its shifted form (e.g., \"ctrl-shift-E\", not \"ctrl-shift-e\")." + } + }, + "type": "object" + } + }, + "type": "object" + }, + "keys": { + "properties": { + "ctrl_tab_behavior_setting": { + "$ref": "#/$defs/CtrlTabBehavior", + "default": "activate_prev_next_tab", + "description": "Controls the behavior of Ctrl+Tab." + } + }, + "type": "object" + }, + "notifications": { + "properties": { + "preferences": { + "$ref": "#/$defs/NotificationsSettings", + "default": { + "is_agent_task_completed_enabled": true, + "is_long_running_enabled": true, + "is_needs_attention_enabled": true, + "is_password_prompt_enabled": true, + "long_running_threshold": 30, + "mode": "unset", + "play_notification_sound": true + }, + "description": "Notification preferences for terminal events." + }, + "toast_duration_secs": { + "default": 8, + "description": "How long notification toasts are displayed, in seconds.", + "type": "integer" + } + }, + "type": "object" + }, + "privacy": { + "properties": { + "crash_reporting_enabled": { + "default": true, + "description": "Whether crash reports are sent.", + "type": "boolean" + }, + "custom_secret_regex_list": { + "default": [], + "description": "Custom regex patterns for detecting and redacting secrets.", + "items": { + "$ref": "#/$defs/CustomSecretRegex" + }, + "type": "array" + }, + "secret_redaction": { + "properties": { + "enabled": { + "default": false, + "description": "Whether secret redaction is enabled to detect and obscure secrets in terminal output.", + "type": "boolean" + }, + "hide_secrets_in_block_list": { + "default": false, + "description": "Whether to hide detected secrets in the block list using asterisks.", + "type": "boolean" + }, + "secret_display_mode_setting": { + "$ref": "#/$defs/SecretDisplayMode", + "default": "strikethrough", + "description": "Controls how detected secrets are visually displayed in the terminal." + } + }, + "type": "object" + }, + "telemetry_enabled": { + "default": true, + "description": "Whether anonymous usage telemetry is collected.", + "type": "boolean" + } + }, + "type": "object" + }, + "session": { + "properties": { + "new_session_shell_override": { + "anyOf": [ + { + "$ref": "#/$defs/NewSessionShell" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The shell to use when opening a new session." + }, + "startup_shell_override": { + "$ref": "#/$defs/StartupShell", + "default": null, + "description": "The shell to use when Warp starts up." + }, + "working_directory_config": { + "$ref": "#/$defs/WorkingDirectoryConfig", + "default": { + "advanced_mode": false, + "global": { + "custom_dir": "", + "mode": "previous_dir" + }, + "new_tab": { + "custom_dir": "", + "mode": "previous_dir" + }, + "new_window": { + "custom_dir": "", + "mode": "previous_dir" + }, + "split_pane": { + "custom_dir": "", + "mode": "previous_dir" + } + }, + "description": "Controls the working directory used when opening new sessions." + } + }, + "type": "object" + }, + "system": { + "properties": { + "linux_selection_clipboard": { + "default": true, + "description": "Whether the Linux primary selection clipboard is used.", + "type": "boolean" + }, + "prefer_low_power_gpu": { + "default": false, + "description": "Whether to prefer the integrated (low-power) GPU.", + "type": "boolean" + }, + "preferred_graphics_backend": { + "anyOf": [ + { + "$ref": "#/$defs/GraphicsBackend" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The preferred graphics backend on Windows." + } + }, + "type": "object" + }, + "terminal": { + "properties": { + "copy_on_select": { + "default": true, + "description": "Whether text is automatically copied to the clipboard when selected.", + "type": "boolean" + }, + "focus_reporting_enabled": { + "default": true, + "description": "Whether to forward focus and blur events to full-screen terminal applications.", + "type": "boolean" + }, + "input": { + "properties": { + "alias_expansion_enabled": { + "default": false, + "description": "Whether shell alias expansion is enabled in the input.", + "type": "boolean" + }, + "at_context_menu_in_terminal_mode": { + "default": true, + "description": "Whether the @ context menu is available in terminal mode.", + "type": "boolean" + }, + "autosuggestions": { + "properties": { + "enabled": { + "default": true, + "description": "Whether command autosuggestions are shown.", + "type": "boolean" + }, + "keybinding_hint": { + "default": true, + "description": "Whether autosuggestion keybinding hints are displayed.", + "type": "boolean" + }, + "show_ignore_button": { + "default": false, + "description": "Whether the ignore button is shown for autosuggestions.", + "type": "boolean" + } + }, + "type": "object" + }, + "classic_completions_mode": { + "default": false, + "description": "Whether classic completions mode is enabled.", + "type": "boolean" + }, + "command_corrections": { + "default": true, + "description": "Whether command corrections are suggested for mistyped commands.", + "type": "boolean" + }, + "completions_open_while_typing": { + "default": false, + "description": "Whether the completions menu opens automatically while typing.", + "type": "boolean" + }, + "enable_slash_commands_in_terminal": { + "default": true, + "description": "Whether slash commands are available in the terminal input.", + "type": "boolean" + }, + "error_underlining_enabled": { + "default": true, + "description": "Whether command errors are underlined in the input.", + "type": "boolean" + }, + "extra_meta_keys": { + "$ref": "#/$defs/ExtraMetaKeys", + "default": { + "left_alt": false, + "right_alt": false + }, + "description": "Controls which additional keys are treated as meta keys." + }, + "honor_ps1": { + "default": false, + "description": "Whether to use your shell's PS1 prompt instead of the Warp prompt.", + "type": "boolean" + }, + "input_box_type_setting": { + "$ref": "#/$defs/InputBoxType", + "default": "classic", + "description": "The terminal input style." + }, + "middle_click_paste_enabled": { + "default": true, + "description": "Whether middle-click pastes from the clipboard.", + "type": "boolean" + }, + "outline_codebase_symbols_for_at_context_menu": { + "default": true, + "description": "Whether codebase symbols appear in the @ context menu.", + "type": "boolean" + }, + "show_hint_text": { + "default": true, + "description": "Whether hint text is shown in the terminal input.", + "type": "boolean" + }, + "show_terminal_input_message_bar": { + "default": true, + "description": "Whether the terminal input message bar is shown.", + "type": "boolean" + }, + "syntax_highlighting": { + "default": true, + "description": "Whether syntax highlighting is enabled in the terminal input.", + "type": "boolean" + } + }, + "type": "object" + }, + "maximum_grid_size": { + "default": 50000, + "description": "The maximum number of rows in the terminal grid.", + "type": "integer" + }, + "mouse_reporting_enabled": { + "default": true, + "description": "Whether to forward mouse events to full-screen terminal applications.", + "type": "boolean" + }, + "scroll_reporting_enabled": { + "default": true, + "description": "Whether to forward scroll events to full-screen terminal applications.", + "type": "boolean" + }, + "show_terminal_zero_state_block": { + "default": true, + "description": "Whether to show the AI zero-state block in new terminal sessions.", + "type": "boolean" + }, + "smart_select": { + "properties": { + "enabled": { + "default": true, + "description": "Whether double-click smart selection is enabled for URLs, emails, file paths, and identifiers.", + "type": "boolean" + }, + "word_char_allowlist": { + "default": "-.~/\\", + "description": "Characters that are considered part of a word for double-click selection when smart select is disabled.", + "type": "string" + } + }, + "type": "object" + }, + "use_audible_bell": { + "default": false, + "description": "Whether to play an audible bell sound on terminal bell events.", + "type": "boolean" + } + }, + "type": "object" + }, + "text_editing": { + "properties": { + "autocomplete_symbols": { + "default": true, + "description": "Whether matching symbols like brackets and quotes are auto-completed.", + "type": "boolean" + }, + "vim_mode_enabled": { + "default": false, + "description": "Whether Vim keybindings are enabled.", + "type": "boolean" + }, + "vim_status_bar": { + "default": true, + "description": "Whether the Vim status bar is displayed.", + "type": "boolean" + }, + "vim_unnamed_system_clipboard": { + "default": false, + "description": "Whether the Vim unnamed register uses the system clipboard.", + "type": "boolean" + } + }, + "type": "object" + }, + "warp_drive": { + "properties": { + "enabled": { + "default": true, + "description": "Whether Warp Drive is enabled.", + "type": "boolean" + }, + "sorting_choice": { + "$ref": "#/$defs/DriveSortOrder", + "default": "by_object_type", + "description": "The sort order for items in Warp Drive." + } + }, + "type": "object" + }, + "warpify": { + "properties": { + "ssh": { + "properties": { + "enable_legacy_ssh_wrapper": { + "default": true, + "description": "Whether the legacy SSH wrapper is enabled for SSH sessions.", + "type": "boolean" + }, + "enable_ssh_warpification": { + "default": true, + "description": "Whether to enable Warp features in SSH sessions.", + "type": "boolean" + }, + "ssh_extension_install_mode": { + "$ref": "#/$defs/SshExtensionInstallMode", + "default": "always_ask", + "description": "Controls SSH extension installation behavior." + }, + "ssh_hosts_denylist": { + "default": [], + "description": "SSH hosts that should not trigger the warpification prompt.", + "items": { + "type": "string" + }, + "type": "array" + }, + "use_ssh_tmux_wrapper": { + "default": false, + "description": "Whether to use a tmux-based wrapper for SSH warpification.", + "type": "boolean" + } + }, + "type": "object" + }, + "subshells": { + "properties": { + "added_subshell_commands": { + "default": [], + "description": "Additional regex patterns for commands that should be recognized as subshells.", + "items": { + "type": "string" + }, + "type": "array" + }, + "subshell_commands_denylist": { + "default": [], + "description": "Commands that should not trigger the subshell warpification prompt.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "workflows": { + "properties": { + "show_global_workflows_in_universal_search": { + "default": false, + "description": "Whether to show global workflows in universal search results.", + "type": "boolean" + } + }, + "type": "object" + } + }, + "title": "Warp Settings", + "type": "object" +} \ No newline at end of file diff --git a/.warp/references/terminology.md b/.warp/references/terminology.md new file mode 100644 index 0000000..3768d96 --- /dev/null +++ b/.warp/references/terminology.md @@ -0,0 +1,237 @@ +# Warp terminology + +Use this glossary everywhere you write about Warp. Keep definitions short, concrete, and consistent. If a term is likely unfamiliar outside developer audiences, include a short plain-language explanation you can reuse on first mention. + +For the summary of the most critical terms (core features, Oz terms, terms to avoid), see the [Terminology standards](../../AGENTS.md#terminology-standards) section of AGENTS.md. This file is the full canonical reference. + +## Core product terms + +- **Agent** / **Agents** — Warp's AI feature for turning natural language into actions (answers, commands, code changes, and workflows). + *Usage note:* Capitalize when referring to the feature: "Agent," "Agents." + +- **Agent Mode** — The mode where Warp interprets your input as a request to an Agent (not a shell command). + *Usage note:* Not "agent mode" or "Agent-mode." + +- **Auto-detection Mode** — The mode where Warp automatically detects whether input is a command or a prompt. + *Usage note:* Useful in onboarding and "how it works" content. + +- **Block** / **Blocks** — Warp's structured unit of terminal output and history. + *Usage note:* Use for navigation, sharing, and "how Warp organizes your terminal." + +- **Command** — A shell command you run in the terminal. + *Usage note:* Keep distinct from "prompt." + +- **Prompt** — A natural-language request you give to an Agent. + *Usage note:* Keep distinct from "command." + +- **Terminal Mode** — The mode where Warp interprets your input as shell commands. + *Usage note:* Use when contrasting with Agent Mode. + +- **Universal Input** — Warp's main input surface that supports both commands and Agent prompts. + *Usage note:* Use as the name of the feature, not "input box." + +- **Warp** — The agentic development environment for professional developers, built around a modern terminal and AI agents. + *Usage note:* Use "Warp" as the product name. Add "AI terminal" only when you need the positioning shorthand. Do not use "Warp Terminal" unless specifically distinguishing from Oz. + +## Navigation and UI terms + +- **Admin Panel** — The team administration interface. + *Usage note:* Capitalize as a UI name. + +- **Agent Management Panel** — The interface for managing Agent configurations, permissions, and activity. + *Usage note:* Capitalize as a UI surface name. Avoid "agent dashboard," "dashboard of agents," or "agent manager." + +- **Command Palette** — The searchable menu for actions and navigation in Warp. + *Usage note:* Capitalize as a UI name. + +- **Session** — A terminal session context (often tied to a tab/pane). + *Usage note:* Don't use "session" to mean "conversation." + +- **Settings** — Warp's configuration interface. + *Usage note:* Capitalize as a UI name. The Settings sidebar has three **umbrellas** (**Agents**, **Code**, and **Cloud platform**) that expand into subpages — always reference the specific subpage in paths, not the umbrella alone. + - **Agents** umbrella subpages: **Oz**, **Profiles**, **MCP servers**, **Knowledge**, **Third party CLI agents**. + - **Code** umbrella subpages: **Indexing and projects**, **Editor and Code Review**. + - **Cloud platform** umbrella subpages: **Environments**, **Oz Cloud API Keys**. + - Deprecated labels to avoid: + - **Settings** > **AI** — now under the **Agents** umbrella; pick the relevant subpage (**Oz** for the global toggle + Active AI/Input/Voice/Other/Experimental; **Profiles** for permissions and allow/denylists; **Knowledge**; **Third party CLI agents**). + - **Settings** > **Platform** — now **Settings** > **Cloud platform** > **Oz Cloud API Keys** for `oz agent` API keys. + - **Settings** > **MCP Servers** (top-level) — now **Settings** > **Agents** > **MCP servers**. + - **Settings** > **Environments** (top-level) — now **Settings** > **Cloud platform** > **Environments**. + +- **Tab** / **Pane** / **Window** — Warp's layout primitives: tabs within windows; panes are splits inside a tab/window. + *Usage note:* Use precisely to avoid confusing layouts. + +## Agent concepts + +- **Ambient Agents** — Oz agents that run automatically in the background on a schedule or trigger, without interactive input. + *Usage note:* Capitalize as a feature/section name. Use lowercase "ambient agents" only when describing the generic concept of agents running in the background. + +- **Agent Profiles** — Saved configurations that define how an Agent runs (for example, permissions and model selection). + *Usage note:* Use when describing "choose how your Agent behaves." + +- **Context** — Inputs attached to a prompt to improve accuracy (files, Blocks, images, URLs, selections). + *Usage note:* Prefer "attach context" / "add context." + +- **Conversation** — A threaded interaction with an Agent, including history and attached context. + *Usage note:* Use "conversation" consistently in product and support content. + +- **Global Rules** — Rules that apply across all projects. + +- **Permissions** — Controls for what an Agent is allowed to do (run commands, edit files, access tools). + *Usage note:* Use for safety, review, and trust messaging. + +- **Project Rules** — Rules that apply within a specific repo, stored in `WARP.md`. + +- **Rules** — Saved guidelines that steer how Agents respond and behave. + *Usage note:* Treat as a feature name. + +- **Slash Commands** — Built-in commands you run by typing `/` to trigger actions (or run saved prompts). + +## Coding terms (Warp features) + +- **Code** — Warp's coding experience for agent-assisted changes (editing, diffs, code review). + *Usage note:* Use when describing "prompt-to-change" workflows. + +- **Codebase Context** — Warp's ability to index a Git-tracked repo so Agents can understand the full codebase. + *Usage note:* Good first-mention explanation: "Codebase Context helps Agents find the right files and make accurate repo-wide changes." + +- **Code Review** — Warp's diff review experience for inspecting, refining, and applying code changes. + *Usage note:* Treat as the feature name. + +## Warp Drive terms + +- **Environment Variable** / **Environment Variables** — Saved environment variables in Warp Drive, shared across sessions and teams. + *Usage note:* Capitalize when referring to the Warp Drive feature; lowercase when referring to generic shell environment variables. + +- **Notebook** / **Notebooks** — Rich documents in Warp Drive for sharing instructions, runbooks, and runnable content. + +- **Prompt** / **Prompts** — Saved natural-language prompts in Warp Drive, reusable across conversations. + *Usage note:* Capitalize when referring to the Warp Drive object type. Use lowercase "prompt" when referring generically to any natural-language request given to an Agent. + +- **Warp Drive** — Warp's place to save and reuse developer artifacts (Workflows, Notebooks, Prompts, Rules, Environment Variables). + *Usage note:* Good first-mention explanation: "Warp Drive is where Warp stores reusable pieces of your workflow." + +- **Workflow** / **Workflows** — Saved, runnable workflows in Warp Drive (often multi-step command sequences). + +## Oz terminology + +### Oz vs Warp + +- **Warp** is the terminal and coding surface +- **Oz** is Warp's programmable agent for running and coordinating agents at scale +- There is typically one Warp environment per user session. Oz can run many agents concurrently, across machines, repos, and teams. + +### Core Oz terms + +- **Environment** — The execution context for an Oz agent, including repo access, dependencies, secrets, compute, and runtime configuration. + +- **Oz** — Warp's programmable agent for running and coordinating agents at scale. + *Example:* With Oz, you can orchestrate multiple agents to automate and parallelize complex workflows. + +- **Oz agent** — A combination of agent instructions (skill or prompt), trigger (cron, webhook, manual), environment (local, cloud), profile, and host. Agents can be local or cloud, and interactive or ambient. + *Example:* Launch an Oz agent from the CLI, the web app, an API or SDK, or directly inside Warp. + +- **Oz cloud agent** — An Oz agent running in the cloud, from a trigger, schedule, or started from someone's local machine. Cloud agents can be interactive or ambient. + +- **Oz conversation** — An interactive execution lifecycle within the Warp Terminal. An Oz conversation is interactive, started in the terminal regardless of whether it's local or in the cloud. + +- **Oz dashboard** — The app surface to manage all Oz runs, unified across the Warp app and web. + +- **Oz run** — A single execution lifecycle of an Oz agent, including actions, outputs, and logs. An Oz run is always ambient and cloud-based. + +- **Oz subagent** — A child Oz agent created by a parent Oz agent to parallelize or delegate work. + +- **Oz web app** — The web app for configuring Oz agents and managing runs. + +### Oz CLI commands + +- `oz agent run` — Run a local agent +- `oz agent run-cloud` — Run an adhoc cloud agent +- `oz environment create/list/get/update/delete` — CRUD on environments +- `oz integration create` — Install integrations (Slack, Linear) +- `oz run list/get` — Get info on ambient agent runs +- `oz schedule create/list/get/update/delete` — CRUD on scheduled ambient agents +- `oz secret create/list/update/delete` — CRUD on Warp-managed secrets + +### Preferred phrases + +- ✅ "Ask Oz to..." +- ✅ "Oz can help you..." +- ✅ "What would you like Oz to do?" + +### Terms to avoid + +- ❌ "Ozzies" → Use "Oz agents", "instances", or "Oz subagents" +- ❌ "Deploying an Oz" → Use "Deploying an Oz agent" +- ❌ "The Oz Agent" → Use "An Oz agent" or "A parent Oz agent" +- ❌ "Oz is running" → Use "An Oz agent is running" or "A run is in progress" +- ❌ "AI agents" → Use "agents" (the "AI" prefix is redundant) + +## Platform terms + +- **Agent API** — The HTTP API for triggering and inspecting Platform runs programmatically. + +- **Host** — Where a task executes (Warp-hosted or customer-hosted). + +- **Integration** / **Integrations** — Configured connections between Warp and external tools (Slack, Linear, GitHub Actions) that trigger runs and post results back. + *Usage note:* Use for the configured connection, not "plugin." + +- **Outputs** — What a run produces (PRs, messages, reports, transcripts). + +- **Run** — The tracked unit of work for a run, including status and outputs. + *Usage note:* Use when describing observability, history, and auditability. + +- **SDK** — Official client libraries for the Agent API (for example, TypeScript SDK, Python SDK). + *Usage note:* Spell out the language on first mention. + +- **Trigger** — The event that starts a run (Slack mention, schedule, CI event, API call). + +- **Warp CLI** — The command-line tool for running and managing Warp Platform workflows. Formerly called `warp-cli`, now `oz`. + +## Technical terms + +- **AI** — not "A.I." Normalize all instances to "AI." +- **allowlist** / **denylist** — use instead of "whitelist" / "blocklist" +- **codebase** — one word, lowercase (unless part of a feature name like "Codebase Context") +- **command-line** — hyphenated when used as an adjective +- **Git repository** or **repo** — not "git repository" (capitalize "Git") +- **macOS** — not "Mac OS" or "Mac" + +## Branded and informal terms + +- **Warpify** / **Warpification** — Productized terms for enabling Warp features in SSH and subshell sessions. + *Usage note:* Acceptable in docs. Used across Warpify documentation and changelogs. + +- ❌ **Warping** — Avoid ad-hoc verbing ("Warping into a session"). Use "using Warp" or the specific action ("open in Warp," "enable Warpify"). + +- ❌ **YOLO mode** — Avoid in formal docs and UI copy. Prefer "Run until completion" or "Full autonomy." Acceptable only as a colloquial parenthetical if absolutely necessary. + +## Open source + +- **`warpdotdev/warp`** — The public, open source repository for Warp's client at [github.com/warpdotdev/warp](https://github.com/warpdotdev/warp). Use this as the canonical link when pointing readers at the source code. + *Usage note:* Lowercase `warp` in the repo path. The display org/name appears in code-formatting; do not write "`Warpdotdev/Warp`" or "`warpdotdev/Warp`." + +- **AGPL v3** — The license under which Warp's client is published. + *Usage note:* Write as "AGPL v3," not "AGPLv3," "AGPL-3.0," or "GNU AGPLv3." Link the first mention to the `LICENSE` file in the repo. + +- **open source** — Preferred phrasing when describing Warp. + *Usage note:* Lowercase "open source" (no hyphen) in prose, except in quoted feature names. Both "Warp is an open source Agentic Development Environment" and "Warp's client is open source under AGPL v3" are acceptable. Use the shorter framing for landing pages and marketing-adjacent copy; use the longer framing when the client/server distinction matters (security pages, contributor docs). + +- **`warp-oss`** / **WarpOss** — The OSS build identity. Lowercase `warp-oss` for the binary, CLI references, and per-channel data dirs (`~/.warp-oss` on macOS, `~/.local/share/warp-oss` on Linux, `AppData\warp\WarpOss` on Windows). CamelCase `WarpOss` for the macOS app bundle name. + *Usage note:* Use only when documenting self-built binaries or the OSS channel. Do not use for the official Warp app. + +- ❌ **OpenWarp** — Pre-launch internal codename for the OSS build. Replaced by `warp-oss` / `WarpOss` in 2026-04. Do not use anywhere in docs. + +## Billing and credits + +- **Add-on Credits** — capitalized as a product feature name +- **Cloud Agent Credits** — capitalized as a billing feature name +- **credits** — the unit of usage for AI features in Warp (lowercase, not "AI credits") +- **plan credits** — credits included with a subscription plan + +## External product names + +- **GitHub Actions** — capitalize "GitHub" +- **GitHub App** — GitHub's installation/auth mechanism used for repo access in integrations +- **Linear** — capitalize +- **Slack** — capitalize diff --git a/.warp/rules/oz-style-guidelines.md b/.warp/rules/oz-style-guidelines.md new file mode 100644 index 0000000..561ab24 --- /dev/null +++ b/.warp/rules/oz-style-guidelines.md @@ -0,0 +1,223 @@ +# Oz and Warp Positioning Briefing + +This document provides comprehensive guidance for writing about Warp and Oz products in enterprise documentation, based on the Warp Positioning Bible and official messaging guidelines. + +## Product Architecture + +### What is Warp? +Warp is an AI development company with two core products: + +1. **Warp terminal** - A modern terminal designed for agentic development where developers can run commands, collaborate with agents, and orchestrate autonomous work from the command line +2. **Oz** - A cloud-based orchestration platform for running, managing, and orchestrating coding agents at scale + +Together, Warp and Oz form a complete **Agentic Development Environment** where local, cloud, interactive, and autonomous agents work together to help developers ship faster without losing control. + +### Warp vs Warp terminal +- **"Warp"** can refer to either the company or the terminal product +- When discussing both the company and terminal product in the same context, use **"Warp"** for the company and **"Warp terminal"** for the product +- It's not necessary to always say "Warp terminal" - context determines usage + +**Correct examples:** +- "Warp is a modern terminal built for coding with agents" +- "Warp is an AI development company" +- "Warp has two products, Warp terminal and Oz" + +## Positioning Pillars + +When writing about Warp products or features, tie back to at least one of these five positioning pillars: + +1. **House of agents** - Warp is embedded in the ecosystem, supporting all the best models, CLI coding agents, and standards like Skills and AGENTS.md +2. **Integrated control plane** - Warp provides a unified set of tools to launch, orchestrate, and manage local, cloud, and autonomous agents +3. **Easy to start, but deeply configurable** - Warp works out of the box, but products are deeply customizable and programmable +4. **Collaborative by design** - Warp facilitates collaboration between developers, their teams, and their agents +5. **Developer in control** - Warp is designed to empower developers and keep them in control, not replace them + +## Oz Terminology and Capitalization + +### Core Oz Terms + +- **Oz** - Warp's programmable platform for running and coordinating agents at scale +- **Oz agent** - A combination of agent instructions (skill or prompt), trigger (cron, webhook, manual), environment (local, cloud), profile, and host. Can be local or cloud, interactive or ambient +- **Oz cloud agent (general)** - An Oz agent running in the cloud, from a trigger, schedule, or started from someone's local machine +- **Oz subagent** - A child Oz agent created by a parent Oz agent to parallelize or delegate work +- **Oz run** - A single execution lifecycle of an Oz agent, including actions, outputs, and logs. Always ambient and cloud-based +- **Oz conversation** - An interactive execution lifecycle within Warp terminal, regardless of whether it's local or in the cloud +- **Environment** - The execution context for an Oz agent, including repo access, dependencies, secrets, compute, and runtime configuration +- **Oz dashboard** - The app surface to manage all Oz runs, unified across the Warp app and web +- **Oz web app** - The web app for configuring Oz agents and managing runs + +### Capitalization Rules + +**Cloud agents:** +- **Product** (capitalized): "Oz Cloud Agent" or "Oz Cloud Agents" when referring to Warp's specific product feature + - "Oz Cloud Agents send you session sharing links" + - "Launch an Oz Cloud Agent from the CLI" +- **Concept** (lowercase): "cloud agent" or "cloud agents" when referring to the general concept + - "Running cloud agents lets you escape the limits of your local machine" + - "The cloud agent architecture enables scalability" + +**Other terms:** +- Use "agents" not "AI agents" (redundant) +- "Skills" not "skills" (capitalized) +- "AGENTS.md" not "agents.md" (all caps) + +### Terms to Avoid + +❌ **Don't use:** +- "Ozzies" → Use "Oz agents", "instances", or "Oz subagents" +- "Deploying an Oz" → Use "Deploying an Oz agent" +- "The Oz Agent" → Use "An Oz agent" or "A parent Oz agent" +- "Oz is running" → Use "An Oz agent is running" or "A run is in progress" +- "AI agents" → Use "agents" +- "Warp's terminal" → Use "Warp" or "Warp terminal" + +### Important Context About Oz + +**All agents in Warp are Oz agents**, whether they are running in the cloud or running locally. + +Oz exists to take agent workflows beyond a single prompt or a single laptop, making them scalable, autonomous, collaborative, and auditable. + +## Target Audience: Professional Developers + +Warp is for **professional developers and teams** building and maintaining production-grade software. Specific characteristics: + +- Working across large, multi-repo systems +- Using the command line daily +- Not terminal nerds +- Full-stack developers, DevOps engineers, data scientists, ICs, tech leads + +While students, designers, and product managers may use Warp, they are not our core audience. + +## Messaging by Audience + +### For End Users (PLG) +Emphasize: +- Parallel agent workflows +- Automating tasks they don't want to do +- Building apps on top of agents +- Scaling beyond what their laptop can support +- Focusing more on work they enjoy +- Continuing tasks on the go (not team collaboration) + +### For Enterprise Buyers +Emphasize: +- Embedding agents through the SDLC +- Programming agents +- All the scaffolding built in +- Flexibility and safe agent execution +- Collaboration across teams +- Connect features to specific values: engineering productivity, safe agent execution, shorter product backlogs + +## Key Messaging Points + +### Warp's Unique Advantages + +**Warp terminal:** +- Modern terminal UI with block-based navigation and command completions +- Code editing features that give developers full visibility and control +- House of agents - integrated with all major CLI coding agents (Oz, Claude Code, Codex, Copilot) +- Unified local <> cloud agents for seamless workflows +- Built-in knowledge store for collaboration + +**Oz:** +- No vendor lock-in - works with any model, with or without Warp +- Real codebases at enterprise scale - multi-repo environments +- Easy to start, deeply programmable +- Integrated local <> cloud agents +- Auto-tracking with full visibility and auditing +- Collaboration baked in with access control + +### What We Are NOT + +Avoid framing Warp as: +- An IDE replacement (we bring in select IDE features but aren't building an IDE) +- An AI "engineer" +- A cheap agent wrapper + +**Note:** We don't care about the traditional terminal vs IDE distinction. Building the best place for agent-first workflows requires bringing in the best of both tools. + +## Voice and Style + +### Do's: +- **Talk about outcomes, not hype** - Show what changes when agents are reliable and orchestrated +- **Emphasize control and trust** - Warp augments developers, doesn't replace them +- **Anchor on production** - Real software, real workflows, real scale +- **Lean into the ecosystem** - We're neutral and support all top models and agents +- **Show impact** - Use numbers, stories, and real-world use cases +- **Make it applicable** - Give developers something useful to take away +- **Champion the developer** - Speak like a developer, respect their knowledge and time +- **Keep it practical** - Skip fluff, provide clear actionable insights + +### Don'ts: +- Avoid overly-strong marketing language +- Don't use corporate or disconnected language +- Skip theoretical posts without practical value +- Don't list features without context or problem-solving + +## Writing Guidelines + +### Headers +- Use sentence case (not title case) +- Capitalize only proper nouns + +### Lists +- List items end in periods when the item is a full sentence +- Otherwise, list items don't end with periods +- Descriptive text and captions end in periods + +### Preferred Phrases +- ✅ "Ask Oz to..." +- ✅ "Oz can help you..." +- ✅ "What would you like Oz to do?" + +## Problem Framing + +### What Developers Struggle With + +**Multi-agent workflows:** +- Running more than 3-4 agents before losing track +- Balancing autonomy with safety + +**Agents get tasks 80% right:** +- Hard to see exactly what agents have done +- Difficult to continue tasks locally +- Forced to switch between terminals and IDEs + +**Staying current:** +- Trying new models and tools daily +- Too much switching and comprehension overhead + +**Breaking of flow:** +- Context-switching between tools +- Constant babysitting and supervision of AI +- Resource-heavy and slow tools + +### What Teams Struggle With + +- Embedding AI tooling across whole teams +- AI adoption doesn't compound across teams +- Running agents safely at scale +- Avoiding vendor lock-in +- Keeping control of agent infrastructure + +## Warp's Point of View + +**The command line is the best place to do agentic development, but the terminal needs to be modernized.** + +The terminal is the natural home for agentic development because: +- It orchestrates systems, processes, and environments +- It spans local and remote work +- It spans the entire SDLC + +Modernizing the terminal unlocks a fundamentally better way to build software with: +- Audit trails and visibility +- Modern UI around commands, code editing, and agent prompting +- Collaboration features that mirror real-world workflows + +## Enterprise Value Proposition + +Organizations adopt Warp Enterprise to: +- **Accelerate development velocity** - AI agents automate tedious tasks across the SDLC +- **Maintain security and control** - Deploy on your infrastructure, route AI inference through your cloud accounts, enforce team-wide guardrails +- **Scale best practices** - Share team knowledge, coding standards, and operational runbooks +- **Reduce context switching** - Keep developers in the terminal with integrated AI, code editing, and tool integrations diff --git a/.warp/skills/answer_question/SKILL.md b/.warp/skills/answer_question/SKILL.md new file mode 100644 index 0000000..1029e01 --- /dev/null +++ b/.warp/skills/answer_question/SKILL.md @@ -0,0 +1,84 @@ +--- +name: answer_question +description: Answer questions about Warp, Oz, agents, terminal features, billing, pricing, troubleshooting, privacy, skills, MCP, integrations, or any other Warp-related topic. Use when a user, support person, or engineer asks a question that can be answered from Warp's documentation. Searches the docs, synthesizes a comprehensive answer, and provides links to relevant doc pages. +--- + +# Answer Question + +Answer any question about Warp or Oz by searching the documentation in this repository and synthesizing a comprehensive, matter-of-fact response with links to source pages. For deep technical questions, also search Warp's source repositories for implementation details. + +## Workflow + +### 1. Search for relevant docs + +The documentation lives in `docs/` with these sections: +- `src/content/docs/` — Warp Terminal and IDE (getting started, terminal, code editor, knowledge & collaboration) +- `src/content/docs/agent-platform/` — Agent Platform (local agents, cloud agents, capabilities, integrations) +- `src/content/docs/reference/` — Technical reference (Oz CLI, API & SDK) +- `src/content/docs/support-and-community/` — Support (troubleshooting, billing, privacy) +- `src/content/docs/enterprise/` — Enterprise +- `src/content/docs/changelog/` — Changelog + +Search strategy: +- Use `codebase_semantic_search` on the docs repo to find relevant doc pages for the user's question. +- Use `grep` when searching for exact feature names, settings, CLI commands, or specific terms. +- Read matched files to gather authoritative content. Skim broadly first, then read key sections in detail. +- If the question spans multiple topics (e.g. "How do skills work with cloud agents?"), search each topic independently and cross-reference. +- Check `astro.config.mjs (sidebar config)` files in the relevant section if you need to locate a page by name. + +### 2. Search source code (if needed) + +For technical questions where the docs are insufficient, incomplete, or you want to validate your answer, search Warp's source repositories: + +- **warp-internal** — Client-side code (Rust, Swift). Contains terminal features, editor, UI, Agent Mode client logic, Warp Drive, etc. +- **warp-server** — Server-side code (Go). Contains API endpoints, cloud agent orchestration, billing, auth, etc. + +To find these repos, search for directories named `warp-internal` and `warp-server` on the user's machine. If not found, ask the user where they are. + +Use source code to: +- Verify technical behavior, edge cases, or implementation details that docs don't fully cover +- Find exact CLI flag names, config options, or API parameters +- Understand how features interact under the hood +- Answer "how does X actually work?" questions that go beyond the docs + +Both repos are indexed for `codebase_semantic_search`. Use `grep` for exact symbol/function names. + +**Important:** Docs are the primary source of truth for user-facing answers. Use source code as supplementary context, not as a replacement. Always prefer doc-based explanations when available. + +### 3. Compose the answer + +- Be direct and matter-of-fact. Answer the question, don't summarize the docs. +- Be comprehensive — cover what the user needs to fully understand the answer — but don't pad with tangential information. +- Use Warp's standard terminology from `AGENTS.md` and the full glossary in `.warp/references/terminology.md`. Key rules: capitalize feature names (Agent, Agent Mode, Warp Drive, Codebase Context), use "Oz agent" not "Ozzie" or "the Oz Agent", use "credits" not "AI credits." +- If the docs do not cover the topic, say so honestly. Do not guess or fabricate information. + +### 4. Generate doc links + +Every answer must end with a **Relevant docs** section listing links to the source pages used. + +URL mapping rules (file path → published URL): + +| File path | URL | +|---|---| +| `src/content/docs/{path}.mdx` | `https://docs.warp.dev/{path}` | +| `src/content/docs/agent-platform/{path}.mdx` | `https://docs.warp.dev/agent-platform/{path}` | +| `src/content/docs/reference/{path}.mdx` | `https://docs.warp.dev/reference/{path}` | +| `src/content/docs/support-and-community/{path}.mdx` | `https://docs.warp.dev/support-and-community/{path}` | +| `src/content/docs/enterprise/{path}.mdx` | `https://docs.warp.dev/enterprise/{path}` | +| `src/content/docs/changelog/{path}.mdx` | `https://docs.warp.dev/changelog/{path}` | + +Key rules: +- **`src/content/docs/` is the homepage space** — the `warp/` prefix is NOT included in URLs. Example: `src/content/docs/terminal/blocks/block-basics.mdx` → `https://docs.warp.dev/terminal/blocks/block-basics` +- All other spaces include the space name in the URL. Example: `src/content/docs/agent-platform/capabilities/skills.mdx` → `https://docs.warp.dev/agent-platform/capabilities/skills` +- Strip the `.mdx` extension. +- `index.mdx` resolves to the parent directory path. Example: `src/content/docs/agent-platform/cloud-agents/integrations/index.mdx` → `https://docs.warp.dev/agent-platform/cloud-agents/integrations` + +### 5. Output format + +``` +[Direct, comprehensive answer to the question] + +**Relevant docs:** +- [Page title](https://docs.warp.dev/...) +- [Page title](https://docs.warp.dev/...) +``` diff --git a/.warp/skills/check_for_broken_links/SKILL.md b/.warp/skills/check_for_broken_links/SKILL.md new file mode 100644 index 0000000..e0b979d --- /dev/null +++ b/.warp/skills/check_for_broken_links/SKILL.md @@ -0,0 +1,169 @@ +--- +name: check_for_broken_links +description: Check the Warp Astro Starlight documentation for broken links by scanning source markdown files. Run the diagnostic script, review the output, fix broken links, and optionally notify Slack. +--- + +# Check for Broken Links + +This skill checks the Warp Astro Starlight documentation for broken links by scanning source markdown files directly. It can optionally send results to a Slack channel. + +## Running the Check + +From the docs repo root: + +```bash +python3 .warp/skills/check_for_broken_links/check_links.py +``` + +### Options + +- `--internal-only`: Only check internal links (fast, no HTTP requests) +- `--external-only`: Only check external links +- `--timeout N`: HTTP timeout in seconds (default: 10) +- `--output FILE`: Save results to JSON file +- `--slack-notify`: Send results to Slack (requires `SLACK_BOT_TOKEN` and `SLACK_CHANNEL_ID` env vars) +- `--slack-channel ID`: Override the default Slack channel + +### Quick internal-only check: + +```bash +python3 .warp/skills/check_for_broken_links/check_links.py --internal-only +``` + +## Output Format + +The script outputs a report like: + +``` +=== BROKEN LINK REPORT === +Files scanned: 174 +Internal links checked: 800 +External links checked: 360 +Broken links found: 5 + +### INTERNAL (3 broken) + +src/content/docs/code/code-overview.md:77 + Link: ../agents/slash-commands.md + Error: File not found + Suggestion: Try ../agent-platform/agent/slash-commands.md + +### EXTERNAL (2 broken) + +src/content/docs/getting-started/what-is-warp.md:42 + Link: https://example.com/old-page + Error: HTTP 404 +``` + +## Fixing Broken Links + +After running the script, fix each broken link based on the error type: + +### Internal Links + +1. **File not found**: The target file doesn't exist + - Check if the file was moved/renamed and update the path + - If content was removed, remove the link or find an alternative + - Check for typos in the path + +2. **Case mismatch**: Path exists but with different casing + - Fix the case to match the actual filename (Astro Starlight is case-sensitive) + +3. **Missing .mdx extension**: Directory link doesn't resolve + - Add `.mdx` extension or ensure `index.mdx` exists in the directory + +4. **Cross-space links**: Links between Astro Starlight spaces (warp/, agent-platform/, support-and-community/, reference/) + - **Relative paths do NOT work across spaces** — use absolute URLs instead + - **IMPORTANT: `src/content/docs/` is the docs homepage, so "warp" is NOT included in URLs** + - Files in `src/content/docs/code/code-review.mdx` → `https://docs.warp.dev/code/code-review` + - Files in `src/content/docs/terminal/command-palette.mdx` → `https://docs.warp.dev/terminal/command-palette` + - For other spaces, include the folder name in the URL: + - Files in `src/content/docs/agent-platform/...` → `https://docs.warp.dev/agent-platform/...` + - Files in `src/content/docs/support-and-community/...` → `https://docs.warp.dev/support-and-community/...` + - Example cross-space link: From `agent-platform/` linking to `code/code-review.mdx`: + - ❌ Wrong: `https://docs.warp.dev/warp/code/code-review` + - ✅ Correct: `https://docs.warp.dev/code/code-review` + - **Note**: Old folder names may be outdated (e.g., `support-and-billing` → `support-and-community/troubleshooting-and-support`). Search for the actual file location before constructing the URL. + +### External Links + +1. **HTTP 404**: Page no longer exists + - Find the new URL if the resource moved + - Remove the link if the resource is gone + - Consider linking to an archived version if appropriate + +2. **Timeout/Connection Error**: Temporary issue or site blocking bots + - Re-run the check to confirm it's persistent + - Visit the URL manually to verify + +### Adding Redirects + +If content moved, you can add a redirect in the appropriate `vercel.json (redirects)`: + +```json +{ + "redirects": [ + { "source": "/old/path", "destination": "/new/path" } + ] +} +``` + +## Creating a PR with Fixes + +1. Create a branch: `git checkout -b fix/broken-links` +2. Fix the broken links identified by the script +3. Re-run the script to verify all fixes: `python3 .warp/skills/check_for_broken_links/check_links.py` +4. Commit and create a PR + +## Slack Notifications + +To send results to Slack (useful for CI/CD or ambient agents): + +### Setup (one-time) + +Create a Warp team secret for the Slack bot token: + +```bash +warp secret create SLACK_BOT_TOKEN --team --description "Slack bot token for broken link reports" +``` + +You'll be prompted to enter the token securely. The token needs `chat:write` scope. + +### Usage + +```bash +python3 .warp/skills/check_for_broken_links/check_links.py --internal-only --slack-notify +``` + +For ambient agent runs, the `SLACK_BOT_TOKEN` secret is automatically injected as an environment variable. + +### Custom channel + +To post to a different channel: + +```bash +python3 .warp/skills/check_for_broken_links/check_links.py --slack-notify --slack-channel YOUR_CHANNEL_ID +``` + +## Dependencies + +Requires Python 3.7+ with `requests`: + +```bash +pip3 install requests +``` + +## Link Types Checked + +- Markdown links: `[text](path/to/file.md)` +- Directory links: `[text](code-editor/)` → resolved to `index.mdx` +- Anchor links: `[text](file.md#section)` → file existence checked, anchor not validated +- External URLs: `[text](https://example.com)` +- Video embeds: `` +- Image references: `` and `![alt](path)` + +## Limitations + +- Anchor links (#section) are not validated for heading existence +- Some external sites block automated requests (Twitter, LinkedIn) +- Astro Starlight-specific includes/partials are not followed diff --git a/.warp/skills/check_for_broken_links/check_links.py b/.warp/skills/check_for_broken_links/check_links.py new file mode 100644 index 0000000..7c6aecc --- /dev/null +++ b/.warp/skills/check_for_broken_links/check_links.py @@ -0,0 +1,543 @@ +#!/usr/bin/env python3 +""" +Broken Link Checker for Warp Astro Starlight Documentation + +Scans markdown source files to find and validate links. +- Internal links: validated by checking if the target file exists +- External links: validated via HTTP HEAD requests +- Optional Slack notifications for CI/ambient agent integration +""" + +import argparse +import json +import os +import re +import sys +import time +from pathlib import Path +from urllib.parse import urlparse, unquote + +DEFAULT_SLACK_CHANNEL = os.environ.get("SLACK_CHANNEL_ID", "") + +try: + import requests + HAS_REQUESTS = True +except ImportError: + HAS_REQUESTS = False + +# Regex patterns for extracting links +# Handle both normal links [text](url) and Astro Starlight angle-bracket links [text]() +MARKDOWN_LINK_ANGLE = re.compile(r'\[([^\]]*)\]\(<([^>]+)>\)') +MARKDOWN_LINK_NORMAL = re.compile(r'\[([^\]]*)\]\(([^)<\s][^)\s]*)\)') +MARKDOWN_IMAGE_ANGLE = re.compile(r'!\[([^\]]*)\]\(<([^>]+)>\)') +MARKDOWN_IMAGE_NORMAL = re.compile(r'!\[([^\]]*)\]\(([^)<\s][^)\s]*)\)') +HTML_LINK = re.compile(r']+href=["\']([^"\']+)["\']', re.IGNORECASE) +HTML_IMG = re.compile(r']+src=["\']([^"\']+)["\']', re.IGNORECASE) +# Detects leftover GitBook embed syntax (should be migrated to ) +GITBOOK_EMBED = re.compile(r'\{%\s*embed\s+url=["\']([^"\']+)["\']') + +MARKDOWN_EXTENSIONS = {'.md', '.mdx'} + +# Domains that block bots or are unreliable +SKIP_DOMAINS = {'twitter.com', 'x.com', 'linkedin.com', 'facebook.com', 't.co'} + +# Non-HTTP schemes to skip +SKIP_SCHEMES = {'mailto', 'tel', 'javascript', 'data', 'file', 'warp'} + +# Directories to skip when scanning +SKIP_DIRECTORIES = {'_book', 'node_modules', '.git', '.vercel', 'dist'} + + +class LinkChecker: + def __init__(self, docs_root, timeout=10): + self.docs_root = Path(docs_root).resolve() + self.timeout = timeout + self.files_scanned = 0 + self.internal_checked = 0 + self.external_checked = 0 + self.broken_links = [] + self.external_cache = {} + + # Astro Starlight projects may define additional pages outside + # the content collection (e.g. `src/pages/api.astro` -> /api). + # Collect those routes so absolute links like `/api` resolve. + self.extra_routes = set() + repo_root = self.docs_root + for _ in range(4): + candidate = repo_root / 'src' / 'pages' + if candidate.is_dir(): + break + if repo_root.parent == repo_root: + break + repo_root = repo_root.parent + # Stash the public/ tree so /assets/... and /images/... refs + # can be validated against on-disk files. + self.public_root = repo_root / 'public' + pages_dir = repo_root / 'src' / 'pages' + if pages_dir.is_dir(): + for p in pages_dir.rglob('*'): + if not p.is_file(): + continue + name = p.name + # Skip dynamic routes and non-page outputs. + if '[' in name or name.endswith('.md.ts'): + continue + if p.suffix not in ('.astro', '.md', '.mdx'): + continue + rel = p.relative_to(pages_dir) + route = '/' + str(rel).rsplit('.', 1)[0] + if route.endswith('/index'): + route = route[:-len('index')] + self.extra_routes.add(route.rstrip('/') or '/') + + if HAS_REQUESTS: + self.session = requests.Session() + self.session.headers['User-Agent'] = 'WarpDocsLinkChecker/1.0' + else: + self.session = None + + def find_markdown_files(self): + files = [] + for root, dirs, filenames in os.walk(self.docs_root): + dirs[:] = [d for d in dirs if d not in SKIP_DIRECTORIES] + for f in filenames: + if Path(f).suffix.lower() in MARKDOWN_EXTENSIONS: + files.append(Path(root) / f) + return sorted(files) + + def extract_links(self, filepath): + links = [] + try: + lines = filepath.read_text(encoding='utf-8').splitlines() + in_html_comment = False + in_fenced_code = None + + for line_num, raw_line in enumerate(lines, 1): + line = raw_line + + # Skip fenced code blocks (``` or ~~~) + if in_fenced_code: + fence_char = in_fenced_code[0] + fence_len = len(in_fenced_code) + if re.match(rf'^\s*{re.escape(fence_char)}{{{fence_len},}}\s*$', line): + in_fenced_code = None + continue + + fence_match = re.match(r'^\s*(`{3,}|~{3,})', line) + if fence_match: + in_fenced_code = fence_match.group(1) + continue + + # Strip HTML comments while preserving same-line non-comment text. + cleaned_segments = [] + index = 0 + while index < len(line): + if in_html_comment: + end_comment = line.find('-->', index) + if end_comment == -1: + index = len(line) + break + in_html_comment = False + index = end_comment + 3 + continue + + start_comment = line.find('', start_comment + 4) + if end_comment == -1: + in_html_comment = True + break + index = end_comment + 3 + + line = ''.join(cleaned_segments) + if not line.strip(): + continue + + # Skip inline code spans like `...` + # Skip inline code spans like `...` or ``...`` + line = re.sub(r'(`+)(?:(?!\1).)+\1', '', line) + if not line.strip(): + continue + if not line.strip(): + continue + + # Check angle-bracket links first (they take precedence) + for pattern in [MARKDOWN_LINK_ANGLE, MARKDOWN_IMAGE_ANGLE]: + for match in pattern.finditer(line): + url = match.group(2).strip() + links.append({'url': url, 'line': line_num}) + + # Check normal markdown links (excluding positions already matched by angle-bracket) + for pattern in [MARKDOWN_LINK_NORMAL, MARKDOWN_IMAGE_NORMAL]: + for match in pattern.finditer(line): + url = match.group(2).strip() + # Skip if this looks like it was part of an angle-bracket link + if not url.startswith('>') and '<' not in url: + links.append({'url': url, 'line': line_num}) + + for pattern in [HTML_LINK, HTML_IMG, GITBOOK_EMBED]: + for match in pattern.finditer(line): + url = match.group(1).strip() + links.append({'url': url, 'line': line_num}) + except Exception as e: + print(f"Warning: Could not read {filepath}: {e}", file=sys.stderr) + return links + + def is_external(self, url): + parsed = urlparse(url) + return parsed.scheme in ('http', 'https') + + def should_skip(self, url): + if not url or url.startswith('#'): + return True + parsed = urlparse(url) + if parsed.scheme in SKIP_SCHEMES: + return True + if self.is_external(url): + for domain in SKIP_DOMAINS: + if domain in parsed.netloc: + return True + return False + + def resolve_internal(self, url, source_file): + url = unquote(url.split('#')[0].split('?')[0]) + if not url: + return None + + source_dir = source_file.parent + if url.startswith('/'): + # Absolute links are site-root paths (Starlight routes). Resolve + # them against the content root, not the raw filesystem root. + return self.docs_root / url.lstrip('/').rstrip('/') + return (source_dir / url).resolve() + + def check_internal(self, url, source_file): + # Resolve asset paths (served from public/) against the on-disk + # public tree so we can catch broken /assets/foo.mp4 references + # introduced by a missing file or a typo. + asset_url = url.split('#')[0].split('?')[0] + if asset_url.startswith('/assets/') or asset_url.startswith('/images/'): + if self.public_root.is_dir(): + target = self.public_root / asset_url.lstrip('/') + if target.exists() and target.is_file(): + return True, None, None + return False, "Asset not found in public/", None + # No public/ tree on disk (unexpected): fall back to skipping. + return True, None, None + + # Route defined by a non-collection Astro page under src/pages/ ? + if asset_url.startswith('/') and self.extra_routes: + normalized = asset_url.rstrip('/') or '/' + if normalized in self.extra_routes: + return True, None, None + + target = self.resolve_internal(url, source_file) + if target is None: + return True, None, None + + # Normalize: a Starlight route like `/foo/bar/` can be either a file + # (`foo/bar.mdx`) or a directory with `index.mdx`. Check both. + candidates = [ + target, + Path(str(target) + '.mdx'), + Path(str(target) + '.md'), + target / 'index.mdx', + target / 'index.md', + target / 'README.md', + ] + for c in candidates: + try: + if c.exists() and c.is_file(): + return True, None, None + except OSError: + continue + + # Check case mismatch against the parent directory, if any. + parent = target.parent + if parent.exists(): + name_lower = target.name.lower() + for item in parent.iterdir(): + if item.name.lower() == name_lower and item.name != target.name: + return False, "File not found (case mismatch?)", f"Try: {item.name}" + + return False, "File not found", None + + def check_external(self, url): + if not self.session: + return True, "Skipped (requests not installed)", None + + if url in self.external_cache: + return self.external_cache[url] + + try: + resp = self.session.head(url, timeout=self.timeout, allow_redirects=True) + if resp.status_code == 405: + resp = self.session.get(url, timeout=self.timeout, allow_redirects=True, stream=True) + + if resp.status_code < 400: + result = (True, None, None) + else: + result = (False, f"HTTP {resp.status_code}", None) + except requests.exceptions.Timeout: + result = (False, "Timeout", None) + except requests.exceptions.SSLError: + result = (False, "SSL Error", None) + except requests.exceptions.ConnectionError: + result = (False, "Connection Error", None) + except Exception as e: + result = (False, f"Error: {type(e).__name__}", None) + + self.external_cache[url] = result + return result + + def check_file(self, filepath, check_internal=True, check_external=True): + links = self.extract_links(filepath) + broken = [] + + for link in links: + url = link['url'] + if self.should_skip(url): + continue + + is_ext = self.is_external(url) + + if is_ext and not check_external: + continue + if not is_ext and not check_internal: + continue + + if is_ext: + self.external_checked += 1 + valid, error, suggestion = self.check_external(url) + else: + self.internal_checked += 1 + valid, error, suggestion = self.check_internal(url, filepath) + + if not valid: + broken.append({ + 'file': str(filepath.relative_to(self.docs_root)), + 'line': link['line'], + 'url': url, + 'error': error, + 'suggestion': suggestion, + 'type': 'external' if is_ext else 'internal' + }) + + return broken + + def run(self, check_internal=True, check_external=True): + files = self.find_markdown_files() + total = len(files) + + print(f"Scanning {total} markdown files...") + modes = [] + if check_internal: + modes.append("internal") + if check_external: + modes.append("external") + print(f"Checking: {' + '.join(modes)} links\n") + + for i, filepath in enumerate(files, 1): + rel = filepath.relative_to(self.docs_root) + print(f"\r[{i}/{total}] {rel}", end='', flush=True) + + self.files_scanned += 1 + broken = self.check_file(filepath, check_internal, check_external) + self.broken_links.extend(broken) + + if check_external: + time.sleep(0.05) + + print("\n") + + def print_report(self): + print("=" * 60) + print("BROKEN LINK REPORT") + print("=" * 60) + print(f"Files scanned: {self.files_scanned}") + print(f"Internal links checked: {self.internal_checked}") + print(f"External links checked: {self.external_checked}") + print(f"Broken links found: {len(self.broken_links)}") + print("=" * 60) + + if not self.broken_links: + print("\n✓ No broken links found!") + return + + internal = [l for l in self.broken_links if l['type'] == 'internal'] + external = [l for l in self.broken_links if l['type'] == 'external'] + + if internal: + print(f"\n### INTERNAL ({len(internal)} broken)\n") + for link in internal: + print(f"{link['file']}:{link['line']}") + print(f" Link: {link['url']}") + print(f" Error: {link['error']}") + if link['suggestion']: + print(f" Suggestion: {link['suggestion']}") + print() + + if external: + print(f"\n### EXTERNAL ({len(external)} broken)\n") + for link in external: + print(f"{link['file']}:{link['line']}") + print(f" Link: {link['url']}") + print(f" Error: {link['error']}") + print() + + def get_results(self): + return { + 'docs_root': str(self.docs_root), + 'files_scanned': self.files_scanned, + 'internal_checked': self.internal_checked, + 'external_checked': self.external_checked, + 'broken_count': len(self.broken_links), + 'broken_links': self.broken_links + } + + def format_slack_message(self): + internal = [l for l in self.broken_links if l['type'] == 'internal'] + external = [l for l in self.broken_links if l['type'] == 'external'] + + if not self.broken_links: + return ":white_check_mark: *Broken Link Check Passed*\n\nNo broken links found in Astro Starlight docs." + + lines = [ + ":warning: *Broken Link Check Found Issues*", + "", + f"• Files scanned: {self.files_scanned}", + f"• Internal links checked: {self.internal_checked}", + f"• External links checked: {self.external_checked}", + f"• *Broken links found: {len(self.broken_links)}*", + ] + + if internal: + lines.append(f"\n*Internal ({len(internal)} broken):*") + for link in internal[:10]: + lines.append(f" • `{link['file']}:{link['line']}` → {link['url']}") + if len(internal) > 10: + lines.append(f" _...and {len(internal) - 10} more_") + + if external: + lines.append(f"\n*External ({len(external)} broken):*") + for link in external[:5]: + lines.append(f" • `{link['file']}:{link['line']}` → {link['error']}") + if len(external) > 5: + lines.append(f" _...and {len(external) - 5} more_") + + lines.append("\n_Run the skill to fix these issues._") + return "\n".join(lines) + + +def send_slack_notification(message, channel=DEFAULT_SLACK_CHANNEL): + token = os.environ.get('SLACK_BOT_TOKEN') + if not token: + print("Error: SLACK_BOT_TOKEN environment variable not set", file=sys.stderr) + print("Create it with: warp secret create SLACK_BOT_TOKEN --scope team", file=sys.stderr) + return False + + if not HAS_REQUESTS: + print("Error: 'requests' library required for Slack notifications", file=sys.stderr) + return False + + try: + resp = requests.post( + 'https://slack.com/api/chat.postMessage', + headers={ + 'Authorization': f'Bearer {token}', + 'Content-Type': 'application/json', + }, + json={ + 'channel': channel, + 'text': message, + 'mrkdwn': True, + }, + timeout=10 + ) + data = resp.json() + if not data.get('ok'): + print(f"Slack API error: {data.get('error', 'unknown')}", file=sys.stderr) + return False + print(f"Slack notification sent to channel {channel}") + return True + except Exception as e: + print(f"Failed to send Slack notification: {e}", file=sys.stderr) + return False + + +def find_docs_root(): + """Locate the content root for this Astro Starlight docs site. + + Preference order, from most specific to most general: + 1. `src/content/docs/` relative to cwd or any ancestor (this repo's layout). + 2. `docs/` relative to cwd or any ancestor (older/legacy layout). + 3. Fall back to cwd. + """ + cwd = Path.cwd() + for base in (cwd, *cwd.parents): + starlight = base / 'src' / 'content' / 'docs' + if starlight.is_dir(): + return starlight + for base in (cwd, *cwd.parents): + legacy = base / 'docs' + if legacy.is_dir(): + return legacy + return cwd + + +def main(): + parser = argparse.ArgumentParser(description='Check Astro Starlight docs for broken links') + parser.add_argument('--docs-root', help='Docs root directory (auto-detected if not set)') + parser.add_argument('--internal-only', action='store_true', help='Only check internal links') + parser.add_argument('--external-only', action='store_true', help='Only check external links') + parser.add_argument('--timeout', type=int, default=10, help='HTTP timeout (default: 10)') + parser.add_argument('--output', help='Output JSON file') + parser.add_argument('--slack-notify', action='store_true', + help='Send results to Slack (requires SLACK_BOT_TOKEN and SLACK_CHANNEL_ID env vars)') + parser.add_argument('--slack-channel', default=DEFAULT_SLACK_CHANNEL, + help=f'Slack channel ID (default: {DEFAULT_SLACK_CHANNEL})') + + args = parser.parse_args() + + docs_root = Path(args.docs_root) if args.docs_root else find_docs_root() + + if not docs_root.exists(): + print(f"Error: Docs root not found: {docs_root}", file=sys.stderr) + sys.exit(1) + + check_internal = not args.external_only + check_external = not args.internal_only + + if check_external and not HAS_REQUESTS: + print("Warning: 'requests' not installed, external links will be skipped", file=sys.stderr) + print("Install with: pip3 install requests\n", file=sys.stderr) + + print(f"Docs root: {docs_root}\n") + + checker = LinkChecker(docs_root, timeout=args.timeout) + + start = time.time() + checker.run(check_internal=check_internal, check_external=check_external) + elapsed = time.time() - start + + print(f"Completed in {elapsed:.1f}s\n") + checker.print_report() + + if args.output: + with open(args.output, 'w') as f: + json.dump(checker.get_results(), f, indent=2) + print(f"\nResults saved to: {args.output}") + + if args.slack_notify: + message = checker.format_slack_message() + send_slack_notification(message, channel=args.slack_channel) + + sys.exit(1 if checker.broken_links else 0) + + +if __name__ == '__main__': + main() diff --git a/.warp/skills/create_pr/SKILL.md b/.warp/skills/create_pr/SKILL.md new file mode 100644 index 0000000..874653a --- /dev/null +++ b/.warp/skills/create_pr/SKILL.md @@ -0,0 +1,218 @@ +--- +name: create_pr +description: Create a pull request in the docs repository for the current branch. Use when the user mentions opening a PR, creating a pull request, submitting changes for review, or preparing documentation for merge. +--- + +# create_pr + +## Overview + +This guide covers best practices for creating pull requests in the docs documentation repository, including syncing with main, running linting checks, validating links, and structuring your PR for effective review. + +## Related Skills + +- `draft_docs` - Draft new documentation pages or update existing ones using established style conventions +- `check_for_broken_links` - Check documentation for broken internal and external links before opening PR + +## Pre-PR Checklist + +### 1. Sync with main + +**Always merge main into your feature branch before opening a PR.** + +```bash +git fetch origin +git merge origin/main +``` + +Resolve any merge conflicts locally before opening the PR. + +### 2. Run linting checks + +This repo uses Trunk CLI for linting. Run these checks before opening or updating a PR: + +```bash +# Check for linting issues +trunk check + +# Auto-format files +trunk fmt +``` + +Enabled linters include: +- `markdownlint` - Markdown formatting and style +- `yamllint` - YAML file validation +- `gitleaks` - Secret detection +- `oxipng` - PNG optimization + +:::note +Trunk CLI is not vendored in this repo. Install it separately: https://docs.trunk.io/check/usage +::: + +### 3. Check for broken links + +Run the link checker to validate all internal and external links: + +```bash +# Quick internal-only check (fast, no HTTP requests) +python3 .warp/skills/check_for_broken_links/check_links.py --internal-only + +# Full check including external links +python3 .warp/skills/check_for_broken_links/check_links.py +``` + +Fix any broken links before opening the PR. See the `check_for_broken_links` skill for detailed guidance on fixing different link types. + +### 4. Review your changes + +Before creating a PR, review what you're about to submit: + +```bash +# View commits in your branch +git --no-pager log origin/main..HEAD --oneline + +# View file statistics +git --no-pager diff origin/main...HEAD --stat + +# View full diff +git --no-pager diff origin/main...HEAD +``` + +This helps you: +- Verify all intended changes are included +- Catch unintended changes before review +- Write an accurate PR description + +### 5. Verify astro.config.mjs (sidebar config) updates + +If you added, moved, or renamed any documentation pages: + +- Update the sidebar config in `astro.config.mjs` at the repo root (see AGENTS.md "Navigation and redirects") +- Ensure the page title in the sidebar config matches the H1 title in the document +- Check that the file path is correct + +### 6. Add redirects for moved/renamed pages + +If you renamed or moved a page that's already published: + +- Add a redirect entry to the appropriate `vercel.json (redirects)` file +- For cross-space redirects, use the `scripts/docs_redirects.py` tool +- Check existing redirects first to avoid duplicates + +```json +// Example redirect in vercel.json +{ + "redirects": [ + { "source": "/old/path", "destination": "/new/path" } + ] +} +``` + +## PR Description Guidelines + +Structure your PR description with these sections: + +### Summary +Brief explanation of what the PR accomplishes and why. + +### Changes +Bulleted list of specific changes, organized by file or area: + +```markdown +## Summary +This PR updates the Terminal and Agent modes documentation for the Oz launch. + +## Changes + +### src/content/docs/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes.md +- Added Getting Started section with first-time and existing user experiences +- Updated keyboard shortcuts with comprehensive tables +- Added fork functionality documentation + +### src/content/docs/agent-platform/astro.config.mjs (sidebar config) +- Updated navigation entry title +``` + +### Additional context (optional) +- Link to related issues or discussions +- Screenshots for visual changes +- Notes for reviewers + +## CLI Workflow + +### Check if PR exists for current branch + +```bash +gh pr view --json number,url +``` + +Exit code 0 if PR exists, 1 if not. + +### Create a new PR + +:::caution +**Always use `--body-file` instead of `--body` for PR descriptions.** Documentation PRs frequently contain backticks, quotes, and other special characters that get corrupted by shell escaping when passed inline. Write the description to a file first, then reference it. +::: + +```bash +# 1. Write the description to a temp file using the create_file tool or a heredoc +cat > /tmp/pr-body.md << 'EOF' +## Summary +Description of changes + +## Changes +- Change 1 +- Change 2 + +Co-Authored-By: Oz +EOF + +# 2. Create the PR using the file +gh pr create --title "docs: Add feature documentation" --body-file /tmp/pr-body.md + +# Open in browser to fill details +gh pr create --web +``` + +### Update an existing PR + +```bash +# Edit body using a file (recommended — avoids shell escaping issues) +gh pr edit 123 --body-file /tmp/pr-body.md + +# Edit title only +gh pr edit 123 --title "New title" + +# Add reviewers or labels +gh pr edit 123 --add-reviewer username --add-label documentation +``` + +### View PR status + +```bash +gh pr status +gh pr checks +``` + +## Co-Author Attribution + +When creating commits or PRs with AI assistance, include attribution at the end of every commit message or PR description: + +``` +Co-Authored-By: Oz +``` + +## After Opening the PR + +1. **Monitor for merge conflicts** - If main is updated, merge it into your branch +2. **Respond to review comments** - Address feedback promptly +3. **Re-run checks after changes** - Run `trunk check` and link checker after making updates +4. **Verify Astro Starlight preview** - Astro Starlight automatically generates a preview for PRs; check that rendering looks correct + +## Best Practices + +- **Keep PRs focused** - One logical documentation change per PR when possible +- **Use descriptive titles** - Start with `docs:` prefix for documentation changes +- **Follow the style guide** - Refer to `AGENTS.md` for voice, tone, and formatting conventions +- **Test locally** - Use `npm run dev` to preview changes before opening PR +- **Include context** - Help reviewers understand why changes were made, not just what changed diff --git a/.warp/skills/docs-seo-audit/SKILL.md b/.warp/skills/docs-seo-audit/SKILL.md new file mode 100644 index 0000000..cf45583 --- /dev/null +++ b/.warp/skills/docs-seo-audit/SKILL.md @@ -0,0 +1,277 @@ +--- +name: docs-seo-audit +description: >- + Audit docs.warp.dev for SEO issues like duplicate titles, missing meta + descriptions, title length problems, and H1 tag issues. Crawls the live + sitemap, generates a report, and fixes issues in the source markdown. Use + when asked to check SEO, fix duplicate titles, audit meta tags, improve + search rankings, or run an SEO check on the docs site. +--- + +# SEO Audit + +Crawl the live docs.warp.dev sitemap to find SEO issues and fix them in the source markdown files. + +## Running the audit + +From the docs repo root: + +```bash +python3 .warp/skills/docs-seo-audit/scripts/seo_audit.py \ + --repo-root . \ + --output /tmp/seo-report.json +``` + +The script fetches all pages listed in `https://docs.warp.dev/sitemap.xml` (a sitemap index including sub-sitemaps), extracts SEO metadata from each page's HTML, and checks for issues. + +### Options + +- `--repo-root PATH` — Path to the docs repo root. Enables mapping live URLs to local source files in the report. +- `--output FILE` — Write the JSON report to a file (otherwise prints to stdout). +- `--max-pages N` — Limit to the first N pages (useful for quick testing). +- `--workers N` — Number of concurrent fetch workers (default: 6). + +### Quick test with a small sample + +```bash +python3 .warp/skills/docs-seo-audit/scripts/seo_audit.py --repo-root . --max-pages 20 --output /tmp/seo-sample.json +``` + +## Reading the report + +The JSON report contains: +- `total_pages` — Number of pages scanned +- `total_issues` — Total issues found +- `by_severity` — Counts by severity (`error`, `warning`, `info`) +- `by_type` — Counts by issue type +- `issues` — Array of individual issues, sorted by severity + +Each issue includes: +- `url` — The live page URL +- `source_file` — The local markdown file (if `--repo-root` was provided) +- `severity` — `error` (must fix), `warning` (should fix), or `info` (nice to fix) +- `type` — Issue category (see below) +- `message` — Human-readable description + +### Issue types + +**Errors (must fix)**: +- `duplicate_title` — Multiple pages share the same `` tag. Hurts search rankings and confuses users. +- `missing_title` — Page has no `<title>` tag. +- `fetch_error` — Page could not be fetched. + +**Warnings (should fix)**: +- `duplicate_description` — Multiple pages share the same meta description. +- `missing_description` — Page has no meta description. Search engines may generate a snippet from page content instead. +- `title_too_short` — Title under 20 chars; may not be descriptive enough for search results. +- `title_too_long` — Title over 70 chars; Google will truncate it in search results. +- `missing_h1` — No H1 heading found on the page. +- `multiple_h1` — More than one H1 heading on the page. + +**Info (nice to fix)**: +- `description_too_short` — Description under 50 chars. +- `description_too_long` — Description over 160 chars; will be truncated in search results. +- `og_title_mismatch` — OG title differs from the title tag (usually auto-matched by Astro Starlight). +- `og_description_mismatch` — OG description differs from the meta description. + +## Reporting results + +After running the audit, ALWAYS report the results to the user before taking any action. Include: + +1. **Summary**: Total pages scanned, total issues, breakdown by severity (errors / warnings / info) +2. **Errors first**: List every error-severity issue with the URL, source file, and what's wrong. These are the most impactful and should be fixed. +3. **Warnings**: Summarize warning-severity issues grouped by type (e.g., "58 pages missing meta descriptions"). List specific pages only for the most impactful ones (duplicate titles, duplicate descriptions). +4. **Info**: Briefly note info-level issues with counts. No need to list every page. +5. **If no issues found**: Explicitly tell the user everything looks clean — don't just silently finish. + +Example report format: +``` +SEO audit complete: 276 pages scanned, 183 issues found. + +**Errors (8):** +- Duplicate title "Overview | Agents | Warp" on 4 pages: + - /agent-platform (source: src/content/docs/agent-platform/index.mdx) + - /agent-platform/local-agents/overview (source: src/content/docs/agent-platform/local-agents/overview.mdx) + ... + +**Warnings (108):** +- 58 pages missing meta descriptions (top offenders: ...) +- 33 titles too short (<20 chars) +- 15 titles too long (>70 chars) + +**Info (67):** +- 55 descriptions over 160 chars +- 12 descriptions under 50 chars +``` + +After reporting, ask the user which issues they want to fix before making changes. + +## Fixing issues + +Before making any changes, read these references: +1. `references/gitbook-seo.md` in this skill directory — explains the non-obvious way Astro Starlight generates title tags from astro.config.mjs (sidebar config) link text (not the H1 heading). +2. `AGENTS.md` at the docs repo root — the single source of truth for documentation style, voice, terminology, and formatting. All titles and descriptions you write must follow these conventions (terminology, sentence case, active voice, frontmatter description format). + +### Key principles + +1. **Title tags come from astro.config.mjs (sidebar config) link text**, not the H1 heading. To fix a title, change the link text in the relevant space's `astro.config.mjs (sidebar config)`. +2. **Meta descriptions come from frontmatter**. To fix a description, edit the `description:` field in the page's YAML frontmatter. +3. **OG and Twitter tags mirror title and description** automatically. No separate fix needed. +4. **Changing astro.config.mjs (sidebar config) link text has side effects**: it also changes the sidebar label, breadcrumbs, and prev/next pagination. URLs are NOT affected. +5. **When changing a title, also update the H1** in the markdown file for consistency. + +### Title exceptions + +Some page titles are intentionally short or specific and must **not** be changed, even if they trigger a `title_too_short` warning. Skip these pages and note them as intentional exceptions in your report: + +- **`src/content/docs/changelog/README.md`** (`Changelog`) — "Changelog" is a clear, universally understood industry term. Branding prefixes like "Warp changelog" or "Release changelog" add no descriptive value and this title should remain as-is. +- **`src/content/docs/terminal/appearance/app-icons.md`** (`App icons`) — The article explicitly explains that *custom* app icons are not available to users. Renaming to "Custom app icons" directly contradicts the page content and must be avoided. +- **`src/content/docs/university/README.md`** (`Guides`) — "Guides" is the landing page for the Guides space. The title is clear and matches the space name; prefixing it (e.g., "Developer Guides") adds no value and creates a mismatch with the space title shown in breadcrumbs. + +When the audit flags these pages for `title_too_short`, exclude them from your fix list and include a note in your report explaining they are intentional exceptions. + +If you believe a new title should be added to this exceptions list, flag it for human review before proceeding. + +### Fixing duplicate titles + +This is the most impactful issue. Common causes: +- Multiple pages named `[Overview](...)` under different sections of the same space +- Generic names like `[Getting Started](...)` or `[FAQs](...)` repeated across sections + +Fix by making each astro.config.mjs (sidebar config) link text unique and descriptive. The link text should identify the specific topic, not just the page type. Use sentence case and correct terminology per `AGENTS.md` (e.g., capitalize product feature names like "Agent Mode", "Warp Drive", "Codebase Context"). Example: +- Before: `[Overview](local-agents/overview.mdx)` + `[Overview](cloud-agents/overview.md)` +- After: `[Local Agents Overview](local-agents/overview.mdx)` + `[Cloud Agents Overview](cloud-agents/overview.md)` + +### Fixing missing descriptions + +Add a `description` field to the page's frontmatter: + +```yaml +--- +description: >- + A concise 1-2 sentence summary of what this page covers and what + value it provides to the reader. +--- +``` + +Write descriptions that: +- Summarize the page's content in 50-160 characters +- Include the primary keyword/topic naturally +- Describe user benefit, not just feature existence +- Follow the voice and terminology conventions in `AGENTS.md` (e.g., use "Warp" not "Warp Terminal", "Oz" for the orchestration platform, active voice, user-focused phrasing) + +### Review loop + +After making fixes, review every change before presenting to the user. Run through this checklist, and if anything fails, fix it and re-run the checklist from the top. Only present changes when everything passes. + +- **Does this still mean the same thing?** Titles and descriptions must accurately represent the page content. Read the actual page before writing or rewriting anything. Never invent features, capabilities, or details that aren't on the page. If unsure what the page covers, read it first. +- **Did I introduce a new duplicate?** Scan the full astro.config.mjs (sidebar config) for the space you edited. Verify every link text is unique. This is the most common mistake — fixing one duplicate by picking a name that collides with an existing entry. +- **Does the H1 match?** Every astro.config.mjs (sidebar config) title change needs a corresponding H1 update in the markdown file. Mismatches between sidebar label and page heading confuse readers. +- **Is the terminology right?** Cross-check against `AGENTS.md` and how the feature is actually referred to in the existing docs. Don't rename things to terms that aren't used elsewhere in the docs. +- **Does this read naturally in context?** Consider how the title appears (a) as a sidebar label under its section header, and (b) as a search result: `{Title} | {Space} | Warp`. If it sounds awkward or uses internal jargon that users wouldn't recognize, rephrase. +- **Are descriptions grounded in page content?** Don't write descriptions based on the title alone. Read the page, then summarize what's actually there. +- **Any other improvements nearby?** Look at adjacent entries in the astro.config.mjs (sidebar config). Are there other generic titles ("Overview", "Getting Started", "FAQ") that could become duplicates in the future? Flag them proactively. + +### Delivering changes + +**Interactive (user in the loop):** Present the full list of changes with old → new values so the user can review at a glance. Wait for approval before committing. + +**Autonomous (scheduled agent, CI):** The review loop above is your quality gate. Commit directly and include the old → new summary in the PR description. + +**PR conventions:** +- Title must be prefixed with `Automated SEO fixes:` (e.g., `Automated SEO fixes: resolve duplicate titles in agent-platform and reference spaces`) +- Add the `seo` label to the PR (e.g., `gh pr create --label seo`) + +## Slack notification (optional) + +If instructed to send a report to Slack, post a summary after the audit completes. This works regardless of whether fixes were made. + +1. Check if `BUZZ_SLACK_TOKEN` environment variable exists. +2. If the token exists, send a summary to the channel the user specified (or the channel configured in the agent's instructions). + +**Categorizing issues in the summary:** Before composing the message, cross-reference every issue against the title exceptions list above and check whether the issue has a local source file. Classify each issue into exactly one bucket: +- **Fixed** — issues you resolved in this run +- **Unfixable** — issues with no local source file (e.g., auto-generated API pages) +- **Allowlisted** — issues that match a title exception entry (these are intentional, not problems) +- **Remaining** — everything else (genuine issues that still need attention) + +Only include a section in the Slack message if its count is > 0. Never list allowlisted pages under "Remaining". + +**If a PR was opened**, include the PR link and a summary of what was fixed: + +``` +*SEO Audit — <date>* +<total_pages> pages scanned | <total_issues> issues found + +*Fixed (<count>):* +• Duplicate title "Overview | Agents | Warp" → split into 4 unique titles +• Trimmed 3 overly long descriptions to ≤160 chars + +*Unfixable (<count>):* +• <N> pages missing meta descriptions (auto-generated, no local source) + +*Allowlisted (<count>):* +• <page1>, <page2>, <page3> (intentionally short titles) + +*Remaining (<count>):* +• <N> pages missing meta descriptions +• <N> titles too short/long + +PR: <pr_url> +``` + +**If no issues were found:** + +``` +*SEO Audit — <date>* +<total_pages> pages scanned | ✅ No issues found +``` + +**If issues were found but no fixes made** (report-only run): + +``` +*SEO Audit — <date>* +<total_pages> pages scanned | <total_issues> issues found (<errors> errors, <warnings> warnings, <info> info) + +*Unfixable (<count>):* +• <N> pages missing meta descriptions (auto-generated, no local source) + +*Allowlisted (<count>):* +• <page1>, <page2> (intentionally short titles) + +*Remaining (<count>):* +• <N> duplicate titles +• <N> pages missing meta descriptions +• <N> titles too short/long +``` + +Send using: + +```bash +curl -X POST https://slack.com/api/chat.postMessage \ + -H "Authorization: Bearer $BUZZ_SLACK_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "channel": "<CHANNEL_ID>", + "text": "<formatted_summary>", + "unfurl_links": false, + "unfurl_media": false + }' +``` + +If `BUZZ_SLACK_TOKEN` is not set, skip the notification and note that the token is required. + +## Dependencies + +Python 3.7+ with only standard library modules (no pip install required). + +## Checks performed + +- Duplicate `<title>` tags across all pages +- Duplicate `<meta name="description">` across all pages +- Missing title or description +- Title length outside 20-70 char range +- Description length outside 50-160 char range +- Missing or multiple `<h1>` headings +- Mismatches between title/OG title and description/OG description +- URL-to-source-file mapping for actionable fixes diff --git a/.warp/skills/docs-seo-audit/references/gitbook-seo.md b/.warp/skills/docs-seo-audit/references/gitbook-seo.md new file mode 100644 index 0000000..3978cce --- /dev/null +++ b/.warp/skills/docs-seo-audit/references/gitbook-seo.md @@ -0,0 +1,11 @@ +# How Astro Starlight generates SEO title tags + +Astro Starlight constructs the HTML `<title>` tag as: `{Page Title} | {Space Title} | {Site Title}` + +**The page title comes from the astro.config.mjs (sidebar config) link text, not the H1 heading.** For example, `[Skills](capabilities/skills.md)` in astro.config.mjs (sidebar config) produces `<title>Skills | Agents | Warp`, regardless of what the H1 says in the markdown file. + +This is not documented by Astro Starlight. Their SEO docs only say "the HTML title is based on the page and space title" without specifying that "page title" means the astro.config.mjs (sidebar config) link text. + +Changing the astro.config.mjs (sidebar config) link text also changes the sidebar label, breadcrumbs, and prev/next pagination. It does NOT change the URL (URLs are based on the file path). + +Meta descriptions come from the `description` field in YAML frontmatter — this part is straightforward. diff --git a/.warp/skills/docs-seo-audit/scripts/seo_audit.py b/.warp/skills/docs-seo-audit/scripts/seo_audit.py new file mode 100644 index 0000000..4da0f27 --- /dev/null +++ b/.warp/skills/docs-seo-audit/scripts/seo_audit.py @@ -0,0 +1,436 @@ +#!/usr/bin/env python3 +""" +SEO audit for docs.warp.dev + +Crawls the Astro Starlight sitemap index, fetches every page, and checks for common +SEO issues: + - Duplicate title tags + - Duplicate meta descriptions + - Missing or empty title / description + - Title length outside 20-70 char range + - Description length outside 50-160 char range + - Missing or multiple H1 tags + - OG / Twitter meta mismatches + +Outputs a JSON report to stdout (or --output FILE). +""" + +import argparse +import json +import os +import sys +import time +from collections import defaultdict +from concurrent.futures import ThreadPoolExecutor, as_completed +from html.parser import HTMLParser +from urllib.error import HTTPError, URLError +from urllib.request import Request, urlopen +from xml.etree import ElementTree as ET + +SITEMAP_INDEX_URL = "https://docs.warp.dev/sitemap.xml" +NS = {"sm": "http://www.sitemaps.org/schemas/sitemap/0.9"} +USER_AGENT = "WarpSEOAudit/1.0" +REQUEST_DELAY = 0.15 # seconds between requests to avoid rate-limiting +MAX_WORKERS = 6 + +# --------------------------------------------------------------------------- +# Astro Starlight space → local directory mapping +# --------------------------------------------------------------------------- +# Astro Starlight publishes each space at a URL prefix. The "warp" space is the site +# root (no prefix). All others use their directory name as prefix. +SPACE_MAP = { + "agent-platform": "docs/agent-platform", + "reference": "docs/reference", + "changelog": "docs/changelog", + "support-and-community": "docs/support-and-community", + "enterprise": "docs/enterprise", + "university": "university", +} +# The warp space lives at the site root, so pages like /terminal/blocks map +# to src/content/docs/terminal/blocks. +ROOT_SPACE_DIR = "docs/warp" + +# --------------------------------------------------------------------------- +# HTML parser +# --------------------------------------------------------------------------- + +class SEOHTMLParser(HTMLParser): + """Lightweight parser that extracts SEO-relevant tags from an HTML page.""" + + def __init__(self): + super().__init__() + self.title = None + self.meta_description = None + self.og_title = None + self.og_description = None + self.twitter_title = None + self.twitter_description = None + self.canonical = None + self.h1s = [] + self._in_head = False + self._in_title = False + self._title_parts = [] + self._in_h1 = False + self._h1_parts = [] + self._h1_depth = 0 + + def handle_starttag(self, tag, attrs): + attrs_dict = dict(attrs) + tag_lower = tag.lower() + + if tag_lower == "head": + self._in_head = True + elif tag_lower == "title" and self._in_head: + self._in_title = True + self._title_parts = [] + elif tag_lower == "meta" and self._in_head: + name = attrs_dict.get("name", "").lower() + prop = attrs_dict.get("property", "").lower() + content = attrs_dict.get("content", "") + if name == "description": + self.meta_description = content + elif prop == "og:title": + self.og_title = content + elif prop == "og:description": + self.og_description = content + elif name == "twitter:title" or prop == "twitter:title": + self.twitter_title = content + elif name == "twitter:description" or prop == "twitter:description": + self.twitter_description = content + elif tag_lower == "link" and self._in_head: + if attrs_dict.get("rel", "").lower() == "canonical": + self.canonical = attrs_dict.get("href") + elif tag_lower == "h1": + self._in_h1 = True + self._h1_depth = 1 + self._h1_parts = [] + + def handle_endtag(self, tag): + tag_lower = tag.lower() + if tag_lower == "head": + self._in_head = False + elif tag_lower == "title" and self._in_title: + self._in_title = False + self.title = "".join(self._title_parts).strip() + elif tag_lower == "h1" and self._in_h1: + self._h1_depth -= 1 + if self._h1_depth <= 0: + self._in_h1 = False + text = "".join(self._h1_parts).strip() + if text: + self.h1s.append(text) + + def handle_data(self, data): + if self._in_title: + self._title_parts.append(data) + if self._in_h1: + self._h1_parts.append(data) + + +# --------------------------------------------------------------------------- +# Fetching helpers +# --------------------------------------------------------------------------- + +def fetch(url, retries=2): + """Fetch a URL and return its body as a string.""" + req = Request(url, headers={"User-Agent": USER_AGENT}) + for attempt in range(retries + 1): + try: + with urlopen(req, timeout=15) as resp: + return resp.read().decode("utf-8", errors="replace") + except (HTTPError, URLError, OSError) as exc: + if attempt == retries: + raise + time.sleep(1) + + +def fetch_sitemap_urls(sitemap_index_url): + """Return a list of all page URLs across all sub-sitemaps.""" + body = fetch(sitemap_index_url) + root = ET.fromstring(body) + sub_urls = [loc.text for loc in root.findall(".//sm:sitemap/sm:loc", NS)] + + page_urls = [] + for sub_url in sub_urls: + try: + sub_body = fetch(sub_url) + sub_root = ET.fromstring(sub_body) + for loc in sub_root.findall(".//sm:url/sm:loc", NS): + if loc.text: + page_urls.append(loc.text.strip()) + except Exception as exc: + print(f"Warning: could not fetch sub-sitemap {sub_url}: {exc}", file=sys.stderr) + return page_urls + + +def extract_seo(url): + """Fetch a page and return its SEO metadata dict.""" + try: + html = fetch(url) + except Exception as exc: + return {"url": url, "error": str(exc)} + + parser = SEOHTMLParser() + try: + parser.feed(html) + except Exception: + pass + + return { + "url": url, + "title": parser.title, + "meta_description": parser.meta_description, + "og_title": parser.og_title, + "og_description": parser.og_description, + "twitter_title": parser.twitter_title, + "twitter_description": parser.twitter_description, + "canonical": parser.canonical, + "h1s": parser.h1s, + } + + +# --------------------------------------------------------------------------- +# URL → source file mapping +# --------------------------------------------------------------------------- + +def url_to_source_path(url, repo_root): + """Best-effort mapping from a live URL to the local markdown source file. + + Returns the relative path from repo_root, or None if no file is found. + """ + from urllib.parse import urlparse + parsed = urlparse(url) + path = parsed.path.strip("/") # e.g. "agent-platform/local-agents/overview" + + # Determine which space this URL belongs to + local_dir = None + remainder = path + for prefix, directory in SPACE_MAP.items(): + if path == prefix or path.startswith(prefix + "/"): + local_dir = directory + remainder = path[len(prefix):].strip("/") + break + if local_dir is None: + # Root space (warp) + local_dir = ROOT_SPACE_DIR + remainder = path + + if not remainder: + # Space landing page → README.md + candidate = os.path.join(repo_root, local_dir, "README.md") + return os.path.relpath(candidate, repo_root) if os.path.isfile(candidate) else None + + # Try direct file match: remainder.md + candidate = os.path.join(repo_root, local_dir, remainder + ".md") + if os.path.isfile(candidate): + return os.path.relpath(candidate, repo_root) + + # Try directory landing page: remainder/README.md + candidate = os.path.join(repo_root, local_dir, remainder, "README.md") + if os.path.isfile(candidate): + return os.path.relpath(candidate, repo_root) + + return None + + +# --------------------------------------------------------------------------- +# Analysis +# --------------------------------------------------------------------------- + +# Title tag length limits (Google typically truncates at ~60 chars). +# The "page title" portion is what we control; the " | Space | Warp" suffix +# is appended by Astro Starlight. We check the full rendered title. +TITLE_MIN = 20 +TITLE_MAX = 70 +DESC_MIN = 50 +DESC_MAX = 160 + + +def analyse(pages, repo_root=None): + """Run SEO checks and return a structured report.""" + issues = [] + + # Group by title and description for duplicate detection + titles = defaultdict(list) + descriptions = defaultdict(list) + + for p in pages: + if "error" in p: + issues.append({ + "url": p["url"], + "severity": "error", + "type": "fetch_error", + "message": f"Could not fetch page: {p['error']}", + }) + continue + + url = p["url"] + title = p.get("title") or "" + desc = p.get("meta_description") or "" + h1s = p.get("h1s", []) + + source_file = url_to_source_path(url, repo_root) if repo_root else None + + base = {"url": url} + if source_file: + base["source_file"] = source_file + + # --- Title checks --- + if not title: + issues.append({**base, "severity": "error", "type": "missing_title", + "message": "Page has no tag"}) + else: + titles[title].append(url) + tlen = len(title) + if tlen < TITLE_MIN: + issues.append({**base, "severity": "warning", "type": "title_too_short", + "message": f"Title is only {tlen} chars (min {TITLE_MIN}): \"{title}\""}) + elif tlen > TITLE_MAX: + issues.append({**base, "severity": "warning", "type": "title_too_long", + "message": f"Title is {tlen} chars (max {TITLE_MAX}): \"{title}\""}) + + # --- Description checks --- + if not desc: + issues.append({**base, "severity": "warning", "type": "missing_description", + "message": "Page has no meta description"}) + else: + descriptions[desc].append(url) + dlen = len(desc) + if dlen < DESC_MIN: + issues.append({**base, "severity": "info", "type": "description_too_short", + "message": f"Description is only {dlen} chars (min {DESC_MIN}): \"{desc[:80]}...\""}) + elif dlen > DESC_MAX: + issues.append({**base, "severity": "info", "type": "description_too_long", + "message": f"Description is {dlen} chars (max {DESC_MAX}): \"{desc[:80]}...\""}) + + # --- H1 checks --- + if len(h1s) == 0: + issues.append({**base, "severity": "warning", "type": "missing_h1", + "message": "Page has no H1 heading"}) + elif len(h1s) > 1: + issues.append({**base, "severity": "warning", "type": "multiple_h1", + "message": f"Page has {len(h1s)} H1 headings: {h1s}"}) + + # --- OG / Twitter consistency --- + og_title = p.get("og_title") or "" + if title and og_title and title != og_title: + issues.append({**base, "severity": "info", "type": "og_title_mismatch", + "message": f"OG title differs from <title>: \"{og_title}\" vs \"{title}\""}) + + og_desc = p.get("og_description") or "" + if desc and og_desc and desc != og_desc: + issues.append({**base, "severity": "info", "type": "og_description_mismatch", + "message": f"OG description differs from meta description"}) + + # --- Duplicate detection --- + for title, urls in titles.items(): + if len(urls) > 1: + for u in urls: + source_file = url_to_source_path(u, repo_root) if repo_root else None + entry = {"url": u, "severity": "error", "type": "duplicate_title", + "message": f"Duplicate title ({len(urls)} pages): \"{title}\"", + "duplicate_urls": urls} + if source_file: + entry["source_file"] = source_file + issues.append(entry) + + for desc, urls in descriptions.items(): + if len(urls) > 1: + for u in urls: + source_file = url_to_source_path(u, repo_root) if repo_root else None + entry = {"url": u, "severity": "warning", "type": "duplicate_description", + "message": f"Duplicate description ({len(urls)} pages): \"{desc[:80]}...\"", + "duplicate_urls": urls} + if source_file: + entry["source_file"] = source_file + issues.append(entry) + + # --- Summary --- + severity_counts = defaultdict(int) + type_counts = defaultdict(int) + for i in issues: + severity_counts[i["severity"]] += 1 + type_counts[i["type"]] += 1 + + return { + "total_pages": len(pages), + "total_issues": len(issues), + "by_severity": dict(severity_counts), + "by_type": dict(type_counts), + "issues": sorted(issues, key=lambda x: ("error", "warning", "info").index(x["severity"])), + } + + +# --------------------------------------------------------------------------- +# Main +# --------------------------------------------------------------------------- + +def main(): + parser = argparse.ArgumentParser(description="SEO audit for docs.warp.dev") + parser.add_argument("--sitemap", default=SITEMAP_INDEX_URL, + help="Sitemap index URL (default: %(default)s)") + parser.add_argument("--repo-root", default=None, + help="Path to the docs repo root for source-file mapping") + parser.add_argument("--output", "-o", default=None, + help="Write JSON report to this file instead of stdout") + parser.add_argument("--max-pages", type=int, default=0, + help="Limit to N pages (0 = all, useful for testing)") + parser.add_argument("--workers", type=int, default=MAX_WORKERS, + help=f"Concurrent fetch workers (default: {MAX_WORKERS})") + args = parser.parse_args() + + print(f"Fetching sitemap index: {args.sitemap}", file=sys.stderr) + urls = fetch_sitemap_urls(args.sitemap) + print(f"Found {len(urls)} pages across all sitemaps", file=sys.stderr) + + if args.max_pages > 0: + urls = urls[:args.max_pages] + print(f"Limiting to first {args.max_pages} pages", file=sys.stderr) + + pages = [] + errors = 0 + + print(f"Fetching pages with {args.workers} workers...", file=sys.stderr) + with ThreadPoolExecutor(max_workers=args.workers) as pool: + future_to_url = {} + for i, url in enumerate(urls): + future = pool.submit(extract_seo, url) + future_to_url[future] = url + # Stagger submissions slightly to avoid burst + if i % args.workers == 0 and i > 0: + time.sleep(REQUEST_DELAY) + + for i, future in enumerate(as_completed(future_to_url)): + result = future.result() + pages.append(result) + if "error" in result: + errors += 1 + if (i + 1) % 25 == 0 or i + 1 == len(urls): + print(f" Progress: {i + 1}/{len(urls)} pages fetched ({errors} errors)", + file=sys.stderr) + + report = analyse(pages, repo_root=args.repo_root) + + output_json = json.dumps(report, indent=2) + if args.output: + with open(args.output, "w") as f: + f.write(output_json) + print(f"\nReport written to {args.output}", file=sys.stderr) + else: + print(output_json) + + # Print summary to stderr + print(f"\n=== SEO AUDIT SUMMARY ===", file=sys.stderr) + print(f"Pages scanned: {report['total_pages']}", file=sys.stderr) + print(f"Total issues: {report['total_issues']}", file=sys.stderr) + for sev in ("error", "warning", "info"): + count = report["by_severity"].get(sev, 0) + if count: + print(f" {sev}: {count}", file=sys.stderr) + print(f"\nIssue breakdown:", file=sys.stderr) + for issue_type, count in sorted(report["by_type"].items(), key=lambda x: -x[1]): + print(f" {issue_type}: {count}", file=sys.stderr) + + +if __name__ == "__main__": + main() diff --git a/.warp/skills/draft_conceptual/SKILL.md b/.warp/skills/draft_conceptual/SKILL.md new file mode 100644 index 0000000..0f24b54 --- /dev/null +++ b/.warp/skills/draft_conceptual/SKILL.md @@ -0,0 +1,38 @@ +--- +name: draft_conceptual +description: Draft a new conceptual documentation page or update an existing one. Use for pages that explain what something is, why it exists, and how it works — without step-by-step procedures. Examples include product overviews, architecture explanations, and design philosophy pages. +--- + +# Draft conceptual page + +Draft a conceptual documentation page that explains what a feature or concept is, why it matters, and how it works at a high level. + +## Workflow + +Follow the workflow in `.warp/skills/draft_docs/SKILL.md`, using the **conceptual template** at `.warp/templates/conceptual.md`. + +## Content type rules + +These rules are specific to conceptual pages (from the "Drafting by content type" section of `AGENTS.md`): + +- Explain "what" and "why" before "how" +- Define new terms when they first appear +- Use diagrams or architecture descriptions where they clarify relationships +- **Do NOT include step-by-step procedures** — link to a procedural or quickstart page instead +- Show real-world scenarios, not just abstract descriptions +- Title convention: noun or "About [subject]" + +## Heading case + +All headings (H1–H4) must use **sentence case**: capitalize only the first word and proper feature names. + +- ✅ `## How it works` +- ✅ `## When to use Codebase Context` +- ❌ `## How It Works` +- ❌ `## When To Use Codebase Context` + +## Existing examples + +Read 2-3 of these strong examples to match the existing pattern: +- `src/content/docs/agent-platform/cloud-agents/deployment-patterns.md` +- `src/content/docs/agent-platform/cloud-agents/overview.md` diff --git a/.warp/skills/draft_docs/SKILL.md b/.warp/skills/draft_docs/SKILL.md new file mode 100644 index 0000000..6b44a4e --- /dev/null +++ b/.warp/skills/draft_docs/SKILL.md @@ -0,0 +1,113 @@ +--- +name: draft_docs +description: Draft new Warp documentation pages or update existing ones using established style conventions, with optional source code context from warp-internal and warp-server. +--- + +# Draft Docs + +This skill guides the process of drafting new documentation pages or updating existing ones for Warp's documentation (referred to as "docs"), which lives at https://docs.warp.dev. All style rules, content type structures, formatting standards, and terminology live in `AGENTS.md` at the docs repo root. That file is the single source of truth and must be read before drafting new docs. + +## How to use + +Invoke this skill with any context that describes what you want to document: +- PRDs or feature specs +- Slack threads or meeting notes +- Existing documentation that needs updating +- A description of a feature or concept + +Example: "Use the draft_docs skill to write docs for [feature name] based on this PRD: [context]" + +## Workflow + +When this skill is invoked, follow these steps in order: + +### 1. Gather context +Review all provided context (PRD, spec, existing doc, etc.). Identify: +- What feature or topic is being documented +- Key user benefits and capabilities +- Technical details that need explaining + +### 2. Clarify placement +Ask the user where the doc should live. The docs are organized into sections, each with its own `astro.config.mjs (sidebar config)`: +- `src/content/docs/` - Warp Terminal and IDE → `docs.warp.dev/` +- `src/content/docs/agent-platform/` - Agent Platform → `docs.warp.dev/agent-platform/` +- `src/content/docs/reference/` - Technical reference (CLI, API & SDK) → `docs.warp.dev/reference/` +- `src/content/docs/support-and-community/` - Support → `docs.warp.dev/support-and-community/` +- `src/content/docs/enterprise/` - Enterprise → `docs.warp.dev/enterprise/` +- `src/content/docs/changelog/` - Changelog → `docs.warp.dev/changelog/` + +Also clarify: Is this a new page or an update to an existing page? + +### 3. Read the style guide +Read `AGENTS.md` in the docs repo root. This is required — it contains all voice/tone rules, formatting standards, content type structures, terminology, and the quality checklist. Do not draft without reading it first. + +### 4. Identify the content type and template +Using the "Drafting by content type" section in `AGENTS.md`, determine which content type the page is: + +| Content type | Use when | Template | Skill | +|---|---|---|---| +| **Conceptual** | Explains what/why, no procedures | `.warp/templates/conceptual.md` | `draft_conceptual` | +| **Procedural** | Step-by-step task instructions | `.warp/templates/procedural.md` | `draft_procedural` | +| **Quickstart** | Fast path to a working result | `.warp/templates/quickstart.md` | `draft_quickstart` | +| **Reference** | Structured information for lookup | `.warp/templates/reference.md` | `draft_reference` | +| **Troubleshooting** | Problem → cause → solution | `.warp/templates/troubleshooting.md` | `draft_troubleshooting` | +| **FAQ** | Question-and-answer format | `.warp/templates/faq.md` | `draft_faq` | +| **Guide** | Task-oriented walkthrough (Guides section) | `.warp/templates/guide-page.md` | `draft_guide` | +| **Feature documentation** | Combined conceptual + procedural (most common) | `.warp/templates/feature-doc.md` | `draft_feature_doc` | + +Once the content type is identified: +- Use the corresponding **template** as the starting scaffold for the page. +- If a **type-specific skill** exists (listed above), read it for additional rules and examples specific to that content type. +- Follow the structure and rules for the identified type in `AGENTS.md`. + +### 5. Research existing patterns +Read 2-3 strong examples in the target section to match existing patterns and conventions. + +### 6. Research source code (if needed) +For technical accuracy, optionally look in Warp's source repositories: +- **warp-internal** - Client-side code (Rust, Swift, etc.) +- **warp-server** - Server-side code (Go) + +To find these repos, search for directories named `warp-internal` and `warp-server` on the user's machine. If not found, ask the user where the repos are located. + +Use source code to verify technical behavior, understand feature implementation, and find accurate terminology. + +### 6.5. Critical formatting rules + +These rules are frequently violated by agents. Apply them carefully during drafting: + +- **Sentence case for all headings (H1–H4)** — Capitalize only the first word and proper feature names. ✅ `## How it works` ❌ `## How It Works` +- **Bold + dash format for list items** — `* **Term** - Description`, not `* Term: Description` +- **Bold for UI elements** — Use `**Save**` not `` `Save` `` after action verbs like "click" +- **Bold per-segment for Settings paths** — Use `**Settings** > **AI** > **Knowledge**` not `` `Settings > AI > Knowledge` `` + +### 7. Draft the doc +Create the documentation using the appropriate template from `.warp/templates/`. Follow the structure for the identified content type and all rules in `AGENTS.md`. Each template includes visible bracketed instructions explaining what to put in each section. + +### 8. Run style lint +Run `python3 .warp/skills/style_lint/style_lint.py --changed` on the drafted file to catch formatting and terminology issues before presenting to the user. + +### 9. Review against checklist +Before presenting the draft, verify against the quality checklist in `AGENTS.md`: +- [ ] Frontmatter includes clear description written as a standalone summary +- [ ] Content follows the structure for its content type +- [ ] Terminology matches the glossary (`.warp/references/terminology.md`) +- [ ] Headers use sentence case (with proper feature name capitalization) +- [ ] Lists use bold term + dash + explanation format +- [ ] Cross-references to related features are included +- [ ] Instructions include expected outcomes +- [ ] Images have descriptive alt text + +### 10. Update navigation and redirects +If this is a new page, remind the user to: +- Add it to the relevant section's `astro.config.mjs (sidebar config)`. + +If this page replaces, renames, or moves an existing page, remind the user to add a redirect: +- **Same-space redirect**: Add an entry to the space's `vercel.json (redirects)` file under `redirects:`. +- **Cross-space redirect**: Add the redirect through the Astro Starlight UI (cross-space redirects cannot be managed via `vercel.json (redirects)`). + +Always check the current list of redirects before adding a new one to avoid duplicates. + +## Output + +Present the drafted documentation as a complete markdown file that can be saved directly to the appropriate location in `docs/`. diff --git a/.warp/skills/draft_faq/SKILL.md b/.warp/skills/draft_faq/SKILL.md new file mode 100644 index 0000000..3890e34 --- /dev/null +++ b/.warp/skills/draft_faq/SKILL.md @@ -0,0 +1,38 @@ +--- +name: draft_faq +description: Draft a new FAQ documentation page or update an existing one. Use for pages that collect frequently asked questions about a topic area. Questions are written in the user's voice and grouped by theme. +--- + +# Draft FAQ page + +Draft an FAQ page with questions grouped by theme and answers that lead with a direct response. + +## Workflow + +Follow the workflow in `.warp/skills/draft_docs/SKILL.md`, using the **FAQ template** at `.warp/templates/faq.md`. + +## Content type rules + +These rules are specific to FAQ pages (from the "Drafting by content type" section of `AGENTS.md`): + +- Write questions in the user's voice ("Can I use my own API key?" not "BYOK support"). +- Lead with a direct answer, then provide detail. +- Keep answers concise — link to full documentation for deeper topics. +- Group questions by theme (e.g., "General", "Billing", "Errors"). +- Title convention: "[Feature] FAQs" or "Frequently asked questions" + +## Heading case + +All headings (H1–H4) must use **sentence case**: capitalize only the first word and proper feature names. + +- ✅ `# Cloud Agents FAQs` +- ✅ `## Billing` +- ✅ `### Can I use my own API key?` +- ❌ `# Cloud Agents FAQS` +- ❌ `## Billing And Pricing` + +## Existing examples + +Read 2-3 of these strong examples to match the existing pattern: +- `src/content/docs/agent-platform/getting-started/faqs.md` +- `src/content/docs/support-and-community/plans-and-billing/pricing-faqs.md` diff --git a/.warp/skills/draft_feature_doc/SKILL.md b/.warp/skills/draft_feature_doc/SKILL.md new file mode 100644 index 0000000..0ef4f95 --- /dev/null +++ b/.warp/skills/draft_feature_doc/SKILL.md @@ -0,0 +1,38 @@ +--- +name: draft_feature_doc +description: Draft a new feature documentation page or update an existing one. This is the most common page type in Warp's docs (~75+ pages). Feature docs combine conceptual content (what a feature is and how it works) with procedural content (step-by-step usage instructions) in one page. +--- + +# Draft feature documentation page + +Draft a feature documentation page that combines conceptual and procedural content — explaining what a feature is, then showing how to use it. + +## Workflow + +Follow the workflow in `.warp/skills/draft_docs/SKILL.md`, using the **feature-doc template** at `.warp/templates/feature-doc.md`. + +## Content type rules + +These rules are specific to feature documentation pages (from the "Drafting by content type" section of `AGENTS.md`): + +- Apply the **conceptual** rules to the explanatory sections (explain what and why, define terms, no procedures in the overview). +- Apply the **procedural** rules to the step-by-step sections (motivate steps, expected outcomes, focused steps). +- **Keep the conceptual and procedural sections clearly separated with distinct headers.** Don't let explanation creep into procedures or vice versa. +- Title convention: feature name as noun + +## Heading case + +All headings (H1–H4) must use **sentence case**: capitalize only the first word and proper feature names. + +- ✅ `## How it works` +- ✅ `## Configuring your environment` +- ✅ `## Agent Mode settings` ("Agent Mode" is a proper feature name) +- ❌ `## How It Works` +- ❌ `## Configuring Your Environment` +- ❌ `## Agent Mode Settings` + +## Existing examples + +Read 2-3 of these strong examples to match the existing pattern: +- `src/content/docs/agent-platform/capabilities/skills.md` +- `src/content/docs/agent-platform/cloud-agents/environments.md` diff --git a/.warp/skills/draft_guide/SKILL.md b/.warp/skills/draft_guide/SKILL.md new file mode 100644 index 0000000..808bbe9 --- /dev/null +++ b/.warp/skills/draft_guide/SKILL.md @@ -0,0 +1,79 @@ +--- +name: draft_guide +description: Draft a new guide page for the Guides section (src/content/docs/university/). Use for practical, task-oriented walkthroughs that help developers accomplish a specific goal — like setting up a tool, completing a workflow, or learning a technique. Guides focus on the "how" with real prompts and reproducible results, targeting non-branded search queries. +--- + +# Draft guide page + +Draft a practical guide that walks a developer through accomplishing a specific goal. + +## Workflow + +Follow the workflow in `.warp/skills/draft_docs/SKILL.md`, using the **guide template** at `.warp/templates/guide-page.md`. + +Guide pages live in `src/content/docs/university/` (the Guides Astro Starlight space), not in `docs/`. When placing the file, use these directories: +- `src/content/docs/university/integrations/` — Setup guides for external tools (Claude Code, Codex, MCP servers) +- `src/content/docs/university/developer-workflows/` — Workflow and technique guides (code review, parallel agents, voice input) +- `src/content/docs/university/end-to-end-builds/` — Full app builds from start to finish +- `src/content/docs/university/mcp-servers/` — MCP-specific guides + +The sidebar nav is defined in `src/content/docs/university/astro.config.mjs (sidebar config)`, which organizes guides into topic-based sections. When adding a new guide, place the file in the appropriate directory above and add the nav entry under the matching section in `astro.config.mjs (sidebar config)`: +- **Getting started** — First steps with Warp: setup, appearance, key features +- **Agent workflows** — Using coding agents to explain code, review PRs, run parallel tasks +- **Configuration** — Rules, agent profiles, saved prompts, monorepo sync +- **External tools & integrations** — MCP servers, Ollama, third-party tool setup +- **Build an app in Warp** — End-to-end app builds with AI coding workflows +- **DevOps & infrastructure** — Cloud logs, Docker, Kubernetes, testing, database optimization +- **Frontend & UI** — Building and refining UI components with coding agents + +## Content type rules + +These rules are specific to guide pages (from the "Drafting by content type" section of `AGENTS.md`): + +- **Titles should be task-oriented** and read like a search query. Use shortened titles in the Astro Starlight nav and full descriptive titles in the article H1. +- **For SEO: capture the non-branded query.** Write the title a developer would actually search for, not "How to do X in Warp." Example: "How to Set Up Claude Code" not "How to Set Up Claude Code in Warp." +- All procedural rules apply (focused steps, motivate steps, expected outcomes). +- Link to relevant feature documentation in the main docs (`docs/`) where concepts need deeper explanation. +- When a guide has a companion video, the written content should stand alone. +- The optional **Productivity tips** section should showcase Warp features as natural extensions of the workflow — not as a separate pitch. + +## SEO and AEO optimization + +When drafting a guide, check for relevant SEO and AEO data: + +1. **Use SEO and AEO data** to inform titles, descriptions, and content coverage. The `docs-seo-audit` skill (`.warp/skills/docs-seo-audit/`) can identify technical SEO issues. +2. **Write the frontmatter `description`** to include the primary target keyword naturally. Keep under 160 characters. +3. **Frame the title for non-branded search.** The page should answer the user's actual question, with Warp features as the natural solution in the guide body. + +## Third-party tool accuracy + +When a guide documents a third-party tool (Claude Code, Codex, OpenCode, etc.): + +- **Always verify claims against the tool's official documentation.** Do not infer implementation details (programming language, architecture, framework) from GitHub repo language stats or third-party blog posts. These are frequently wrong or outdated. +- **Link to official docs rather than reproducing install steps.** Installation commands, plan names, pricing, model names, and permission/approval modes change frequently. Link to the tool's official quickstart or setup page and keep the guide focused on the Warp-specific workflow. +- **If you must include specific details** (e.g., exact commands, plan tier names, approval mode names), fetch and verify them from the tool's current official documentation before publishing. Add a note or link so readers can check for updates. +- **Do not include pricing information** for third-party tools — it changes and is hard to keep evergreen. +- **Avoid brand-specific product mentions** that date quickly or exclude users. Use generic terms: "Bluetooth audio device" not "AirPods", "code editor" not a specific IDE unless the guide is about that IDE. +- **Avoid specific model version numbers** (e.g., "GPT-5.4") unless directly relevant. Link to the tool's model documentation instead. + +## Link verification + +Before adding any internal documentation link: + +- **Verify the target page exists.** Check the relevant `astro.config.mjs (sidebar config)` file (`src/content/docs/astro.config.mjs (sidebar config)`, `src/content/docs/agent-platform/astro.config.mjs (sidebar config)`, `src/content/docs/university/astro.config.mjs (sidebar config)`) to confirm the page is listed. Do NOT generate plausible-looking URLs to pages that don't exist. +- **If a target page is planned but not yet published**, link to the closest existing page and add a TODO comment with the intended future path: `<!-- TODO: Update to [future-path] once [page name] is live -->` +- **For third-party agent pages**, the current paths are under `src/content/docs/agent-platform/third-party-agents/` (e.g., `claude-code.mdx`, `codex.mdx`, `opencode.mdx`). + +## Cross-linking + +Every guide should link to: +- At least one other guide in the Guides section +- Relevant feature documentation in the main docs (`src/content/docs/` or `src/content/docs/agent-platform/`) +- If applicable, pages in the Coding Agents section (`src/content/docs/agent-platform/third-party-agents/`) + +## Existing examples + +Read 2-3 of these strong examples to match the existing pattern: +- `university/mcp-servers/sentry-mcp-fix-sentry-error-in-empower-website.mdx` +- `university/end-to-end-builds/building-a-real-time-chat-app-github-mcp-+-railway.mdx` +- `university/developer-workflows/beginner/how-to-explain-your-codebase-using-warp-rust-codebase.mdx` diff --git a/.warp/skills/draft_procedural/SKILL.md b/.warp/skills/draft_procedural/SKILL.md new file mode 100644 index 0000000..e91c4e4 --- /dev/null +++ b/.warp/skills/draft_procedural/SKILL.md @@ -0,0 +1,39 @@ +--- +name: draft_procedural +description: Draft a new procedural documentation page or update an existing one. Use for task-oriented, step-by-step instructions that help a reader accomplish a specific goal. Examples include configuring an integration, creating an API key, or setting up an environment. +--- + +# Draft procedural page + +Draft a procedural documentation page with step-by-step instructions to accomplish a specific goal. + +## Workflow + +Follow the workflow in `.warp/skills/draft_docs/SKILL.md`, using the **procedural template** at `.warp/templates/procedural.md`. + +## Content type rules + +These rules are specific to procedural pages (from the "Drafting by content type" section of `AGENTS.md`): + +- **Keep steps focused, not artificially atomic.** Aim for one primary action per step, but group tightly related actions together when they share the same UI context. Up to ~3 related actions per step is acceptable. +- **Motivate steps before giving instructions.** Briefly explain WHY before HOW, especially for setup steps. +- Include expected outcomes after key steps so the reader can confirm they're on track. +- Test all instructions for accuracy. +- Provide troubleshooting for common failure points. +- Don't over-explain — link to conceptual pages for the "why." +- Title convention: gerund ("Configuring X", "Managing X") + +## Heading case + +All headings (H1–H4) must use **sentence case**: capitalize only the first word and proper feature names. + +- ✅ `# Configuring environments` +- ✅ `## Creating an API key` +- ❌ `# Configuring Environments` +- ❌ `## Creating An API Key` + +## Existing examples + +Read 2-3 of these strong examples to match the existing pattern: +- `src/content/docs/reference/cli/api-keys.md` +- `src/content/docs/agent-platform/cloud-agents/integrations/slack.md` diff --git a/.warp/skills/draft_quickstart/SKILL.md b/.warp/skills/draft_quickstart/SKILL.md new file mode 100644 index 0000000..9a441b5 --- /dev/null +++ b/.warp/skills/draft_quickstart/SKILL.md @@ -0,0 +1,40 @@ +--- +name: draft_quickstart +description: Draft a new quickstart documentation page or update an existing one. Use for first-time experiences that get the reader to a working result fast (~10 minutes). Quickstarts focus on the critical path with minimal prerequisites and link to deeper guides for edge cases. +--- + +# Draft quickstart page + +Draft a quickstart that gets the reader from zero to a working result in about 10 minutes. + +## Workflow + +Follow the workflow in `.warp/skills/draft_docs/SKILL.md`, using the **quickstart template** at `.warp/templates/quickstart.md`. + +## Content type rules + +These rules are specific to quickstart pages (from the "Drafting by content type" section of `AGENTS.md`): + +- **Give every quickstart a descriptive H1 title.** Don't use a bare "Quickstart" — include the feature or topic name. +- Minimize prerequisites — the reader should be able to start quickly. +- Target ~10 minutes or less. +- Keep steps focused on the critical path — defer edge cases and advanced options to other pages. +- Steps can be less formal than full procedural content. Use heavy visual cues (code blocks, screenshots). +- All procedural rules apply (focused steps, motivate steps, expected outcomes). +- End with 2-3 actionable next steps linking to deeper content. +- Title convention: "[Feature] quickstart" or "Quickstart for [product]" + +## Heading case + +All headings (H1–H4) must use **sentence case**: capitalize only the first word and proper feature names. + +- ✅ `# Cloud Agents quickstart` +- ✅ `## Running your first cloud agent` +- ❌ `# Cloud Agents Quickstart` +- ❌ `## Running Your First Cloud Agent` + +## Existing examples + +Read 2-3 of these strong examples to match the existing pattern: +- `src/content/docs/agent-platform/cloud-agents/quickstart.md` +- `src/content/docs/getting-started/quickstart/installation-and-setup.md` diff --git a/.warp/skills/draft_reference/SKILL.md b/.warp/skills/draft_reference/SKILL.md new file mode 100644 index 0000000..5960884 --- /dev/null +++ b/.warp/skills/draft_reference/SKILL.md @@ -0,0 +1,41 @@ +--- +name: draft_reference +description: Draft a new reference documentation page or update an existing one. Use for structured factual information meant for lookup — CLI commands, API endpoints, configuration options, keyboard shortcuts, error codes. Reference pages describe and only describe. +--- + +# Draft reference page + +Draft a reference documentation page with structured, exhaustive information for developer lookup. + +## Workflow + +Follow the workflow in `.warp/skills/draft_docs/SKILL.md`, using the **reference template** at `.warp/templates/reference.md`. + +## Content type rules + +These rules are specific to reference pages (from the "Drafting by content type" section of `AGENTS.md`): + +- Be exhaustive — document every option, flag, and configuration value. +- Use consistent formatting for parameters (e.g., `--flag` in backticks, description as a dash-separated list item). +- Alphabetize entries where ordering doesn't matter. +- Keep descriptions factual and concise — this is for lookup, not learning. +- Include at least one practical example for each command or endpoint. +- **Adopt standard patterns ruthlessly** — consistency is more important than style. Every entry must follow the same structure. +- Structure should mirror the structure of the product it describes. +- Use H2 for sections, H3 for subsections. Tables for multiple elements, lists for single. +- Title convention: noun describing contents ("Keyboard shortcuts", "CLI commands") + +## Heading case + +All headings (H1–H4) must use **sentence case**: capitalize only the first word and proper feature names. + +- ✅ `# CLI commands` +- ✅ `## Running agents` +- ❌ `# CLI Commands` +- ❌ `## Running Agents` + +## Existing examples + +Read 2-3 of these strong examples to match the existing pattern: +- `reference/cli/index.mdx` +- `reference/api-and-sdk/index.mdx` diff --git a/.warp/skills/draft_troubleshooting/SKILL.md b/.warp/skills/draft_troubleshooting/SKILL.md new file mode 100644 index 0000000..915e398 --- /dev/null +++ b/.warp/skills/draft_troubleshooting/SKILL.md @@ -0,0 +1,39 @@ +--- +name: draft_troubleshooting +description: Draft a new troubleshooting documentation page or update an existing one. Use for known issues, common errors, and diagnostic guides. Troubleshooting pages follow a problem → cause → solution format, leading with the symptom the user sees. +--- + +# Draft troubleshooting page + +Draft a troubleshooting page that helps users diagnose and fix common issues. + +## Workflow + +Follow the workflow in `.warp/skills/draft_docs/SKILL.md`, using the **troubleshooting template** at `.warp/templates/troubleshooting.md`. + +## Content type rules + +These rules are specific to troubleshooting pages (from the "Drafting by content type" section of `AGENTS.md`): + +- Use the problem or error message as the header — this helps with search. +- Group related issues under broader category headers (e.g., "SSH", "Shells"). +- Lead with the symptom — the reader arrived because something broke. Don't make them read context before getting to the fix. +- Provide workarounds when a fix isn't available. +- Link to related troubleshooting pages and support channels. +- Include workarounds even when no fix exists — documenting a known issue without a workaround still saves the user time searching. +- Title convention: "Troubleshooting [feature]" or "Error: [error name]" + +## Heading case + +All headings (H1–H4) must use **sentence case**: capitalize only the first word and proper feature names. + +- ✅ `# Troubleshooting environments` +- ✅ `## Agent fails to start` +- ❌ `# Troubleshooting Environments` +- ❌ `## Agent Fails To Start` + +## Existing examples + +Read 2-3 of these strong examples to match the existing pattern: +- `src/content/docs/support-and-community/troubleshooting-and-support/known-issues.md` +- `src/content/docs/reference/cli/troubleshooting.md` diff --git a/.warp/skills/missing_docs/SKILL.md b/.warp/skills/missing_docs/SKILL.md new file mode 100644 index 0000000..7d45795 --- /dev/null +++ b/.warp/skills/missing_docs/SKILL.md @@ -0,0 +1,84 @@ +--- +name: missing_docs +description: >- + Find and fill documentation gaps in Warp's Astro Starlight docs by auditing coverage + against code surfaces in warp-internal and warp-server, then drafting missing + pages. Use when asked to find missing docs, audit documentation coverage, + identify undocumented features, draft docs for new features, or do a docs + coverage check. Runs a Python audit script to identify gaps, then researches + source code and writes first-pass doc pages. Can run audit-only, draft-only, + or end-to-end. +--- + +# Missing Docs + +Find documentation gaps and draft missing pages in one workflow. + +## Two-phase workflow + +### Phase 1: Audit + +Run the audit script to identify gaps: + +```bash +python3 .warp/skills/missing_docs/scripts/audit_docs.py +``` + +Options: +- `--category features|cli|api|staleness` — run a single audit category +- `--severity high|medium|low` — filter by minimum severity +- `--output report.json` — save JSON report to file +- `--warp-internal PATH` — explicit path to warp-internal (auto-detected from sibling dirs) +- `--warp-server PATH` — explicit path to warp-server (auto-detected from sibling dirs) + +The script performs 4 audits: +1. **Feature flag coverage** — compares GA flags in `warp_core/src/features.rs` + `app/Cargo.toml` against doc mentions +2. **CLI command coverage** — compares `warp_cli/src/lib.rs` subcommands against `src/content/docs/reference/cli/` +3. **API endpoint coverage** — compares `router/router.go` routes against `src/content/docs/reference/api-and-sdk/` and the OpenAPI spec +4. **Docs staleness** — checks for outdated terminology in existing docs + +Present the report to the user, grouped by category and sorted by severity. + +### Phase 2: Draft + +For each gap the user wants to address (prioritize high → medium → low): + +1. Read `references/feature_surface_map.md` to determine the target doc section +2. Read `AGENTS.md` in the docs repo root for the complete style guide +3. Read 2-3 strong examples in the target section to match formatting patterns +4. Research the relevant source code: + - **Feature gaps** → read the implementation in warp-internal `app/src/`, check UI code, settings, user-facing strings + - **CLI gaps** → read command definition in `warp_cli/src/`, extract flags, arguments, help text + - **API gaps** → read handler in warp-server `router/handlers/`, route definition, request/response types +5. Draft the doc following style guide conventions: + - YAML frontmatter with description + - **All headings (H1–H4) must use sentence case** — capitalize only the first word and proper feature names (e.g., "Agent Mode", "Warp Drive"). ✅ `## How it works` ❌ `## How It Works` + - Opening paragraph with user benefit + - Key features, how it works, detailed sections, cross-references + - Correct terminology (Agent, Agent Mode, Warp Drive, Oz, etc.) + - Bold + dash format for list items: `* **Term** - Description` +6. Create the markdown file at the suggested path +7. Remind user to add new pages to the relevant `astro.config.mjs (sidebar config)` + +To find warp-internal and warp-server, search for sibling directories of the docs repo. If not found, ask the user. + +### Invocation modes + +The user can trigger either phase or both: +- **"Run a docs audit"** or **"Check docs coverage"** → Phase 1 only +- **"Draft docs for [specific gap]"** → Phase 2 only (skip audit) +- **"Find and fix missing docs"** → Both phases end-to-end + +### Drafting standards + +- Produce complete, ready-to-commit markdown — not outlines or stubs +- For CLI docs: include command syntax, all flags with descriptions, practical examples +- For feature docs: lead with user benefit, include how-to, cross-reference related features +- For API docs: include request/response schemas, auth requirements, curl examples +- Use `codebase_semantic_search` and `grep` on source repos for technical accuracy + +## References + +- `references/feature_surface_map.md` — curated mapping of flags/commands to doc pages, also lists internal-only flags to ignore +- `references/stale_terms.md` — deprecated/outdated terms to flag during staleness audits, sourced from AGENTS.md terminology standards +- `AGENTS.md` (docs repo root) — full documentation style guide diff --git a/.warp/skills/missing_docs/references/feature_surface_map.md b/.warp/skills/missing_docs/references/feature_surface_map.md new file mode 100644 index 0000000..70019d6 --- /dev/null +++ b/.warp/skills/missing_docs/references/feature_surface_map.md @@ -0,0 +1,335 @@ +# Feature Surface Map + +Curated mapping of feature flags, CLI commands, and code modules to their expected documentation pages. +The audit script reads this file to reduce false positives — entries here are verified rather than flagged. + +Format: `CodeIdentifier -> docs/path/to/page.md` (one per line within each section). +Lines starting with `#` are comments. Blank lines are ignored. + +# Maintenance: when a new GA feature flag ships, add a mapping here. +# Run `python3 .warp/skills/missing_docs/scripts/audit_docs.py` to find unmapped flags. +# This audit is also run as a recurring scheduled Oz agent to catch drift. + +## Feature flags -> doc pages + +AgentMode -> src/content/docs/agent-platform/warp-agents/README.md +AgentManagementView -> src/content/docs/agent-platform/cloud-agents/managing-cloud-agents.md +AgentManagementDetailsView -> src/content/docs/agent-platform/cloud-agents/managing-cloud-agents.md +AgentModeComputerUse -> src/content/docs/agent-platform/warp-agents/computer-use.md +AgentModeWorkflows -> src/content/docs/knowledge-and-collaboration/warp-drive/workflows.md +AgentOnboarding -> src/content/docs/agent-platform/getting-started/agents-in-warp.md +AIRules -> src/content/docs/agent-platform/warp-agents/rules.md +AIResumeButton -> src/content/docs/agent-platform/warp-agents/interacting-with-agents/terminal-and-agent-modes.md +CodeReviewView -> src/content/docs/code/code-review.md +InlineCodeReview -> src/content/docs/agent-platform/warp-agents/interactive-code-review.md +FileTree -> src/content/docs/code/code-editor/file-tree.md +CodeFindReplace -> src/content/docs/code/code-editor/find-and-replace.md +VimCodeEditor -> src/content/docs/code/code-editor/code-editor-vim-keybindings.md +McpServer -> src/content/docs/agent-platform/warp-agents/mcp.md +McpOauth -> src/content/docs/agent-platform/warp-agents/mcp.md +ImageAsContext -> src/content/docs/agent-platform/warp-agents/agent-context/images-as-context.md +SelectionAsContext -> src/content/docs/agent-platform/warp-agents/agent-context/selection-as-context.md +DiffSetAsContext -> src/content/docs/agent-platform/warp-agents/agent-context/selection-as-context.md +WebSearchUI -> src/content/docs/agent-platform/warp-agents/web-search.md +WebFetchUI -> src/content/docs/agent-platform/warp-agents/web-search.md +CodebaseContext -> src/content/docs/agent-platform/warp-agents/codebase-context.md +CrossRepoContext -> src/content/docs/agent-platform/warp-agents/codebase-context.md +FullSourceCodeEmbedding -> src/content/docs/agent-platform/warp-agents/codebase-context.md +SearchCodebaseUI -> src/content/docs/agent-platform/warp-agents/codebase-context.md +CloudEnvironments -> src/content/docs/agent-platform/cloud-agents/environments.md +CloudMode -> src/content/docs/agent-platform/cloud-agents/overview.md +AmbientAgentsCommandLine -> src/content/docs/agent-platform/cloud-agents/overview.md +ScheduledAmbientAgents -> src/content/docs/agent-platform/cloud-agents/triggers/scheduled-agents.md +WarpManagedSecrets -> src/content/docs/agent-platform/cloud-agents/secrets.md +IntegrationCommand -> src/content/docs/reference/cli/integration-setup.md +ConversationManagement -> src/content/docs/agent-platform/warp-agents/cloud-conversations.md +ForkConversationFromBlock -> src/content/docs/agent-platform/warp-agents/interacting-with-agents/conversation-forking.md +Voice -> src/content/docs/agent-platform/warp-agents/interacting-with-agents/voice.md +WarpDrive -> src/content/docs/knowledge-and-collaboration/warp-drive/README.md +EnvVars -> src/content/docs/knowledge-and-collaboration/warp-drive/environment-variables.md +CommandPaletteFileSearch -> src/content/docs/terminal/command-palette.md +Themes -> src/content/docs/terminal/appearance/themes.md +Ligatures -> src/content/docs/terminal/appearance/text-fonts-cursor.md +UIZoom -> src/content/docs/terminal/appearance/size-opacity-blurring.md +SSH -> src/content/docs/terminal/warpify/ssh.md +SplitPanes -> src/content/docs/terminal/windows/split-panes.md +Tabs -> src/content/docs/terminal/windows/tabs.md +GlobalHotkey -> src/content/docs/terminal/windows/global-hotkey.md +LaunchConfigurations -> src/content/docs/terminal/sessions/launch-configurations.md +SessionRestoration -> src/content/docs/terminal/sessions/session-restoration.md +BlockBasics -> src/content/docs/terminal/blocks/block-basics.md +Autosuggestions -> src/content/docs/terminal/command-completions/autosuggestions.md +Completions -> src/content/docs/terminal/command-completions/completions.md +CommandHistory -> src/content/docs/terminal/entry/command-history.md +CommandCorrections -> src/content/docs/terminal/entry/command-corrections.md +UsageBasedPricing -> src/content/docs/support-and-community/plans-and-billing/credits.md +APIKeyAuthentication -> src/content/docs/reference/cli/api-keys.md +APIKeyManagement -> src/content/docs/reference/cli/api-keys.md +SecretRedaction -> src/content/docs/support-and-community/privacy-and-security/secret-redaction.md +CreatingSharedSessions -> src/content/docs/knowledge-and-collaboration/session-sharing/README.md +AgentSharedSessions -> src/content/docs/agent-platform/warp-agents/session-sharing.md +ProfilesDesignRevamp -> src/content/docs/agent-platform/warp-agents/agent-profiles-permissions.md +MultiProfile -> src/content/docs/agent-platform/warp-agents/agent-profiles-permissions.md +InlineProfileSelector -> src/content/docs/agent-platform/warp-agents/agent-profiles-permissions.md +ModelChoice -> src/content/docs/agent-platform/warp-agents/model-choice.md +Skills -> src/content/docs/agent-platform/warp-agents/skills.md +ListSkills -> src/content/docs/agent-platform/warp-agents/skills.md +BundledSkills -> src/content/docs/agent-platform/warp-agents/skills.md +Planning -> src/content/docs/agent-platform/warp-agents/planning.md +SyncAmbientPlans -> src/content/docs/agent-platform/warp-agents/planning.md +TaskLists -> src/content/docs/agent-platform/warp-agents/task-lists.md +SlashCommands -> src/content/docs/agent-platform/warp-agents/slash-commands.md +SuggestedRules -> src/content/docs/agent-platform/warp-agents/rules.md +RectSelection -> src/content/docs/terminal/more-features/text-selection.md +ContextWindowUsageV2 -> src/content/docs/agent-platform/warp-agents/interacting-with-agents/README.md +ConfigurableBlockLimits -> src/content/docs/terminal/blocks/block-basics.md +CommandCorrectionKey -> src/content/docs/terminal/entry/command-corrections.md +ClassicCompletions -> src/content/docs/terminal/command-completions/completions.md +DynamicWorkflowEnums -> src/content/docs/knowledge-and-collaboration/warp-drive/workflows.md +SharedWithMe -> src/content/docs/knowledge-and-collaboration/warp-drive/README.md +WarpPacks -> src/content/docs/knowledge-and-collaboration/warp-drive/README.md +TabbedEditorView -> src/content/docs/code/code-editor/README.md +ReadImageFiles -> src/content/docs/agent-platform/warp-agents/agent-context/images-as-context.md +FileRetrievalTools -> src/content/docs/agent-platform/warp-agents/codebase-context.md +ConversationArtifacts -> src/content/docs/agent-platform/warp-agents/interacting-with-agents/README.md +OzChangelogUpdates -> src/content/docs/changelog/README.md +ActiveConversationRequiresInteraction -> src/content/docs/agent-platform/warp-agents/interacting-with-agents/README.md + +# Recently shipped GA features +VerticalTabs -> src/content/docs/terminal/windows/vertical-tabs.md +TabConfigs -> src/content/docs/terminal/windows/tab-configs.md +PluggableNotifications -> src/content/docs/terminal/more-features/notifications.md +RevertToCheckpoints -> src/content/docs/agent-platform/warp-agents/slash-commands.md +RewindSlashCommand -> src/content/docs/agent-platform/warp-agents/slash-commands.md +ForkFromCommand -> src/content/docs/agent-platform/warp-agents/slash-commands.md +SummarizationConversationCommand -> src/content/docs/agent-platform/warp-agents/slash-commands.md +CodeReviewFind -> src/content/docs/code/code-review.md +CodeReviewSaveChanges -> src/content/docs/code/code-review.md +DiscardPerFileAndAllChanges -> src/content/docs/code/code-review.md +AutoOpenCodeReviewPane -> src/content/docs/code/code-review.md +GitOperationsInCodeReview -> src/content/docs/code/code-review.md +AgentView -> src/content/docs/agent-platform/warp-agents/interacting-with-agents/terminal-and-agent-modes.md +AgentViewBlockContext -> src/content/docs/agent-platform/warp-agents/agent-context/blocks-as-context.md +CloudConversations -> src/content/docs/agent-platform/warp-agents/cloud-conversations.md +CloudModeFromLocalSession -> src/content/docs/agent-platform/cloud-agents/overview.md +TeamApiKeys -> src/content/docs/reference/cli/api-keys.md +PRCommentsSlashCommand -> src/content/docs/agent-platform/warp-agents/slash-commands.md +PRCommentsV2 -> src/content/docs/agent-platform/warp-agents/interacting-with-agents/README.md +CLIAgentRichInput -> src/content/docs/agent-platform/cli-agents/rich-input.md +HOANotifications -> src/content/docs/agent-platform/warp-agents/agent-notifications.md +OpenCodeNotifications -> src/content/docs/agent-platform/cli-agents/opencode.md +CodexNotifications -> src/content/docs/agent-platform/cli-agents/codex.md +HOARemoteControl -> src/content/docs/agent-platform/cli-agents/remote-control.md +GlobalSearch -> src/content/docs/code/overview.md +FileBasedMcp -> src/content/docs/agent-platform/warp-agents/mcp.md +ConversationsAsContext -> src/content/docs/agent-platform/warp-agents/agent-context/blocks-as-context.md +GithubPrPromptChip -> src/content/docs/agent-platform/warp-agents/agent-notifications.md +AskUserQuestion -> src/content/docs/agent-platform/warp-agents/interacting-with-agents/README.md +AIContextMenuEnabled -> src/content/docs/agent-platform/warp-agents/agent-context/using-to-add-context.md +AtMenuOutsideOfAIMode -> src/content/docs/agent-platform/warp-agents/agent-context/using-to-add-context.md +AIContextMenuCode -> src/content/docs/agent-platform/warp-agents/agent-context/using-to-add-context.md +DriveObjectsAsContext -> src/content/docs/agent-platform/warp-agents/agent-context/using-to-add-context.md +KittyKeyboardProtocol -> src/content/docs/terminal/more-features/full-screen-apps.md +InlineRepoMenu -> src/content/docs/agent-platform/warp-agents/codebase-context.md +InlineHistoryMenu -> src/content/docs/agent-platform/warp-agents/interacting-with-agents/terminal-and-agent-modes.md +SkillArguments -> src/content/docs/agent-platform/warp-agents/skills.md + +## CLI commands -> doc pages + +# Top-level Oz CLI commands +oz agent -> src/content/docs/reference/cli/README.md +oz environment -> src/content/docs/reference/cli/integration-setup.md +oz mcp -> src/content/docs/reference/cli/mcp-servers.md +oz run -> src/content/docs/reference/cli/README.md +oz model -> src/content/docs/reference/cli/README.md +oz login -> src/content/docs/reference/cli/README.md +oz logout -> src/content/docs/reference/cli/README.md +oz integration -> src/content/docs/reference/cli/integration-setup.md +oz schedule -> src/content/docs/reference/cli/README.md +oz secret -> src/content/docs/reference/cli/README.md +oz provider -> src/content/docs/reference/cli/README.md + +## API endpoints -> doc pages + +# Public API endpoints +POST /agent/run -> src/content/docs/reference/api-and-sdk/README.md +GET /agent/runs -> src/content/docs/reference/api-and-sdk/README.md +GET /agent/runs/{runId} -> src/content/docs/reference/api-and-sdk/README.md + +# Internal/infrastructure endpoints (not part of public API, no docs needed) +GET /block/embed/:id -> internal +GET /block/:id -> internal +GET /referral/:id -> internal +GET /client_version -> internal +GET /client_version/daily -> internal +POST /receive_nps_response -> internal +POST /receive_pmf_response -> internal +GET /current_time -> internal +POST /graphql/v2 -> internal +GET /graphql/v2 -> internal +GET /graphiql -> internal +GET /graphiql/v2 -> internal +GET /download -> internal +GET /download/brew -> internal +GET /download/windows -> internal +GET /download/cli -> internal + +## Flags to ignore (internal-only, not user-facing) + +# These flags are internal implementation details and don't need documentation +CocoaSentry +CrashReporting +CrashRecoveryForceX11 +DebugMode +LogExpensiveFramesInSentry +WithSandboxTelemetry +RecordAppActiveEvents +RuntimeFeatureFlags +FetchChannelVersionsFromWarpServer +SequentialStorage +InBandGeneratorsForSSH +RunGeneratorsWithCmdExe +RecordPtyThroughput +FetchGenericStringObjects +IntegratedGPU +LazySceneBuilding +RemoveAltScreenPadding +MaximizeFlatStorage +SharedBlockTitleGeneration +RetryTruncatedCodeResponses +ReloadStaleConversationFiles +NLDClassifierModelEnabled +ChangedLinesOnlyApplyDiffResult +SendTelemetryToFile +SendEvalMetadata +FileGlobV2Warnings +ExpandEditToPane +MCPGroupedServerContext +MultiAgentParallelToolCalls +AgentDecidesCommandExecution +AgentModePrimaryXML +AgentModePrePlanXML +AgentModeAnalytics +GlobalAIAnalyticsBanner +GlobalAIAnalyticsCollection +FastForwardAutoexecuteButton +LinkedCodeBlocks +V4AFileDiffs +NewWarpingAnimation +NewDiffModel +SummarizationViaMessageReplacement +SummarizationCancellationConfirmation +TabCloseButtonOnLeft +LessHorizontalTerminalPadding +RemoveAutosuggestionDuringTabCompletions +ResizeFix +ForceClassicCompletions +DefaultWaterfallMode +DefaultAdeberryTheme +AutoupdateUIRevamp +MinimalistUI +AvatarInTabBar +SessionSharingAcls +ImeMarkedText +ConvertLegacyMcps +NewTabStyling +AmbientAgentsRTC +OzBranding +OzLaunchModal +GetStartedTab +CreateProjectFlow +CodeLaunchModal +ValidateAutosuggestions +ClearAutosuggestionOnEscape +OzPlatformSkills + +# UI implementation details (not user-facing features) +FallbackModelLoadOutputMessaging +IncrementalAutoReload +CodeReviewScrollPreservation +WarpifyFooter +TransferControlTool +TrimTrailingBlankLines +InlineMenuHeaders +BlocklistMarkdownImages +BlocklistMarkdownTableRendering +PendingUserQueryIndicator +RememberFastForwardState +HoaCodeReview +AgentToolbarEditor +SkipFirebaseAnonymousUser +OpenWarpNewSettingsModes +HOAOnboardingFlow +AgentViewConversationListView +BuildPlanAutoReloadBannerToggle +BuildPlanAutoReloadPostPurchaseModal +UpgradeToProModal +UpgradeToProModalPromo +FreeUserNoAi +SoloUserByok +ForceLogin +SimulateGithubUnauthed +ConversationApi +McpDebuggingIds +ContextLineReviewComments +RichTextMultiselect +ActiveConversationRequiresInteraction + +# Non-GA flags in dogfood/preview only +Orchestration +OrchestrationV2 +OrchestrationEventPush +LSPAsATool +SshRemoteServer +EmbeddedCodeReviewComments +AgentManagementDetailsView +InteractiveConversationManagementView +MarkdownImages +MarkdownMermaid +EditableMarkdownMermaid +OzIdentityFederation +AgentHarness +DirectoryTabColors +ArtifactCommand +AgentViewBlockContext +CloudModeImageContext +CloudModeHostSelector +AmbientAgentsImageUpload +NldImprovements +CodebaseIndexSpeedbump +CodebaseIndexPersistence +SharedSessionWriteToLongRunningCommands +AgentTips +AgentViewPromptChip +AllowOpeningFileLinksUsingEditorEnv +AllowIgnoringInputSuggestions +CodeModeChip +UndoClosedPanes +RevertDiffHunk +ViewingSharedSessions +SettingsImport +BlockToolbeltSaveAsWorkflow +ShellSelector +FullScreenZenMode +WorkflowAliases +KittyImages +GrepTool +NativeShellCompletions +WelcomeTab +DragTabsToWindows +SshDragAndDrop +ITermImages +AIGeneratedOnboardingSuggestions +PartialNextCommandSuggestions +CycleNextCommandSuggestion +AIBlockOverflowMenu +PromptSuggestionsViaMAA +SelectablePrompt +PredictAMQueries +UseTantivySearch +CommandCorrectionsHistoryRule +SuggestedAgentModeWorkflows +ConversationArtifacts +ConversationApi +PRCommentsSkill +FigmaDetection diff --git a/.warp/skills/missing_docs/references/stale_terms.md b/.warp/skills/missing_docs/references/stale_terms.md new file mode 100644 index 0000000..555a2b3 --- /dev/null +++ b/.warp/skills/missing_docs/references/stale_terms.md @@ -0,0 +1,34 @@ +# Stale Terms + +Known outdated or incorrect terminology that should be flagged during audits. +The audit script reads this file to check existing docs for stale language. + +# Format: `term to search for -> reason it's stale` (one per line within each section). +# Lines starting with `#` are comments. Blank lines are ignored. +# All term matching is case-insensitive. + +# Maintenance: when AGENTS.md "Terms to avoid" or "Terminology Standards" changes, +# mirror updates here. Run the audit to verify new terms catch real issues. + +## Renamed or removed features + +warp ai -> Renamed to Agent Mode +ai command -> Legacy term — now Agent Mode +generate command -> Legacy feature — replaced by Agent Mode +warp terminal -> Prefer 'Warp' unless distinguishing from Oz +natural language command -> Legacy term — now Agent Mode + +## Incorrect branding or casing + +ai credits -> Use 'credits' without the AI prefix +mac os -> Use 'macOS' + +## Deprecated terminology + +ozzies -> Use 'Oz agents', 'instances', or 'Oz subagents' +warp agent -> Use 'Agent' or 'Oz agent' depending on context +warp agents -> Use 'Agents' or 'Oz agents' depending on context +agent-mode -> Use 'Agent Mode' (two words, no hyphen) +deploying an oz -> Use 'Deploying an Oz agent' +the oz agent -> Use 'An Oz agent' or 'A parent Oz agent' +oz is running -> Use 'An Oz agent is running' or 'A run is in progress' diff --git a/.warp/skills/missing_docs/scripts/audit_docs.py b/.warp/skills/missing_docs/scripts/audit_docs.py new file mode 100755 index 0000000..f6c0237 --- /dev/null +++ b/.warp/skills/missing_docs/scripts/audit_docs.py @@ -0,0 +1,718 @@ +#!/usr/bin/env python3 +""" +Missing Docs Audit Script for Warp Astro Starlight Documentation + +Compares documentation coverage against code surfaces in warp-internal and +warp-server to identify gaps. Produces a structured JSON report. + +Usage: + python3 .warp/skills/missing_docs/scripts/audit_docs.py + python3 .warp/skills/missing_docs/scripts/audit_docs.py --category features + python3 .warp/skills/missing_docs/scripts/audit_docs.py --output report.json +""" + +import argparse +import json +import os +import re +import sys +from pathlib import Path + +# --------------------------------------------------------------------------- +# Constants +# --------------------------------------------------------------------------- + +SKIP_DIRECTORIES = {"_book", "node_modules", ".git", ".docs"} + +# Paths to reference files (relative to this script) +SCRIPT_DIR = Path(__file__).resolve().parent +SKILL_DIR = SCRIPT_DIR.parent +SURFACE_MAP_PATH = SKILL_DIR / "references" / "feature_surface_map.md" +STALE_TERMS_PATH = SKILL_DIR / "references" / "stale_terms.md" + +# --------------------------------------------------------------------------- +# Surface map parser +# --------------------------------------------------------------------------- + +def parse_surface_map(path: Path) -> dict: + """Parse the feature_surface_map.md into structured data.""" + result = { + "feature_to_doc": {}, + "cli_to_doc": {}, + "api_to_doc": {}, + "ignore_flags": set(), + } + if not path.exists(): + return result + + current_section = None + for line in path.read_text().splitlines(): + line = line.strip() + if not line or line.startswith("#"): + if line.startswith("## Feature flags"): + current_section = "features" + elif line.startswith("## CLI commands"): + current_section = "cli" + elif line.startswith("## API endpoints"): + current_section = "api" + elif line.startswith("## Flags to ignore"): + current_section = "ignore" + continue + + if current_section == "ignore": + result["ignore_flags"].add(line) + continue + + if " -> " in line: + key, doc_path = line.split(" -> ", 1) + key = key.strip() + doc_path = doc_path.strip() + if current_section == "features": + result["feature_to_doc"][key] = doc_path + elif current_section == "cli": + result["cli_to_doc"][key] = doc_path + elif current_section == "api": + result["api_to_doc"][key] = doc_path + + return result + + +def parse_stale_terms(path: Path) -> list[tuple[str, str]]: + """Parse stale_terms.md into a list of (term, reason) tuples.""" + terms = [] + if not path.exists(): + return terms + + for line in path.read_text().splitlines(): + line = line.strip() + if not line or line.startswith("#"): + continue + if " -> " in line: + term, reason = line.split(" -> ", 1) + terms.append((term.strip().lower(), reason.strip())) + return terms + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +def find_repo(name: str, explicit_path: str | None, docs_root: Path) -> Path | None: + """Find a sibling repo by name, or use the explicit path.""" + if explicit_path: + p = Path(explicit_path).resolve() + if p.exists(): + return p + print(f"Warning: explicit path {explicit_path} does not exist", file=sys.stderr) + return None + + # Try sibling directory (docs is at .../code/docs, look for .../code/<name>) + sibling = docs_root.parent / name + if sibling.exists(): + return sibling + return None + + +def find_markdown_files(docs_root: Path) -> list[Path]: + """Recursively find all markdown files under docs_root.""" + files = [] + for root, dirs, filenames in os.walk(docs_root): + dirs[:] = [d for d in dirs if d not in SKIP_DIRECTORIES] + for f in filenames: + if f.endswith(".md") or f.endswith(".mdx"): + files.append(Path(root) / f) + return sorted(files) + + +def read_all_docs_text(docs_root: Path) -> dict[str, str]: + """Read all doc files into a dict of {relative_path: content}.""" + result = {} + for f in find_markdown_files(docs_root): + try: + rel = str(f.relative_to(docs_root.parent)) # relative to docs root + result[rel] = f.read_text(encoding="utf-8").lower() + except Exception: + pass + return result + + +def camel_to_search_terms(flag_name: str) -> list[str]: + """Convert a CamelCase flag name into searchable terms. + + e.g. AgentModeComputerUse -> ['agent mode computer use', 'computer use', 'agentmodecomputeruse'] + """ + # Split on camel case boundaries + words = re.sub(r"([a-z])([A-Z])", r"\1 \2", flag_name).split() + terms = [] + + # Full phrase + full = " ".join(w.lower() for w in words) + terms.append(full) + + # Last 2-3 words (the most distinctive part) + if len(words) > 2: + terms.append(" ".join(w.lower() for w in words[-2:])) + terms.append(" ".join(w.lower() for w in words[-3:])) + + # Lowercase concatenated (matches code references) + terms.append(flag_name.lower()) + + # snake_case version + snake = "_".join(w.lower() for w in words) + terms.append(snake) + + return list(dict.fromkeys(terms)) # dedupe preserving order + + +def search_docs_for_terms(docs_text: dict[str, str], terms: list[str]) -> list[str]: + """Search all docs for any of the given terms. Return matching file paths.""" + matches = [] + for path, content in docs_text.items(): + for term in terms: + if term in content: + matches.append(path) + break + return matches + +# --------------------------------------------------------------------------- +# Audit 1: Feature flag coverage +# --------------------------------------------------------------------------- + +def parse_feature_flags(warp_internal: Path) -> list[str]: + """Parse FeatureFlag enum variants from features.rs.""" + # The FeatureFlag enum lives in the warp_features crate + features_rs = warp_internal / "crates" / "warp_features" / "src" / "lib.rs" + if not features_rs.exists(): + # Fall back to legacy path + features_rs = warp_internal / "warp_core" / "src" / "features.rs" + if not features_rs.exists(): + print(f"Warning: {features_rs} not found", file=sys.stderr) + return [] + + content = features_rs.read_text() + # Match enum variants (lines like " AgentMode," or " AgentMode {") + # inside the FeatureFlag enum + in_enum = False + flags = [] + for line in content.splitlines(): + stripped = line.strip() + if "enum FeatureFlag" in stripped: + in_enum = True + continue + if in_enum: + if stripped == "}": + break + # Skip comments, attributes, empty lines + if stripped.startswith("//") or stripped.startswith("#[") or stripped.startswith("///") or not stripped: + continue + # Extract variant name + match = re.match(r"^([A-Z]\w+)", stripped) + if match: + flags.append(match.group(1)) + return flags + + +def parse_default_features(warp_internal: Path) -> set[str]: + """Parse the default feature list from app/Cargo.toml.""" + cargo_toml = warp_internal / "app" / "Cargo.toml" + if not cargo_toml.exists(): + print(f"Warning: {cargo_toml} not found", file=sys.stderr) + return set() + + content = cargo_toml.read_text() + # Find the default = [...] block + match = re.search(r'default\s*=\s*\[(.*?)\]', content, re.DOTALL) + if not match: + return set() + + features_block = match.group(1) + # Extract quoted feature names + return set(re.findall(r'"(\w+)"', features_block)) + + +def snake_to_pascal(snake: str) -> str: + """Convert snake_case to PascalCase: agent_mode -> AgentMode.""" + return "".join(word.capitalize() for word in snake.split("_")) + + +def audit_features(warp_internal: Path, docs_root: Path, surface_map: dict, + docs_text: dict[str, str]) -> list[dict]: + """Audit feature flag coverage in docs.""" + flags = parse_feature_flags(warp_internal) + default_features = parse_default_features(warp_internal) + ignore_flags = surface_map.get("ignore_flags", set()) + feature_to_doc = surface_map.get("feature_to_doc", {}) + + findings = [] + for flag in flags: + # Skip ignored flags + if flag in ignore_flags: + continue + + # Determine if GA (in default features) + snake = re.sub(r"([a-z])([A-Z])", r"\1_\2", flag).lower() + is_ga = snake in default_features + + # Skip non-GA features (they're behind flags and may not need docs yet) + if not is_ga: + continue + + # Check if mapped in surface map + if flag in feature_to_doc: + doc_path = feature_to_doc[flag] + full_path = docs_root.parent / doc_path + if full_path.exists(): + continue # Mapped and doc exists — verified + else: + findings.append({ + "flag": flag, + "search_terms": camel_to_search_terms(flag), + "severity": "high", + "suggested_doc_path": doc_path, + "reason": f"Mapped doc {doc_path} does not exist", + }) + continue + + # Not in surface map — search docs for mentions + terms = camel_to_search_terms(flag) + matches = search_docs_for_terms(docs_text, terms) + if not matches: + findings.append({ + "flag": flag, + "search_terms": terms, + "severity": "medium", + "suggested_doc_path": None, + "reason": "GA feature with no doc mentions found", + }) + + return findings + +# --------------------------------------------------------------------------- +# Audit 2: CLI command coverage +# --------------------------------------------------------------------------- + +def parse_cli_commands(warp_internal: Path) -> list[dict]: + """Parse CLI subcommands from warp_cli/src/lib.rs.""" + lib_rs = warp_internal / "warp_cli" / "src" / "lib.rs" + if not lib_rs.exists(): + return [] + + content = lib_rs.read_text() + commands = [] + + # Find CliCommand enum variants + in_enum = False + for line in content.splitlines(): + stripped = line.strip() + if "enum CliCommand" in stripped: + in_enum = True + continue + if in_enum: + if stripped == "}": + break + # Match lines like "Agent(crate::agent::AgentCommand)," + match = re.match(r"^([A-Z]\w+)(?:\(|,|\s*$)", stripped) + if match: + name = match.group(1) + # Convert PascalCase to lowercase command name + cmd_name = re.sub(r"([a-z])([A-Z])", r"\1-\2", name).lower() + # Find source file + source_match = re.search(rf"crate::(\w+)::", stripped) + source_file = f"warp_cli/src/{source_match.group(1)}.rs" if source_match else None + commands.append({ + "name": name, + "command": f"oz {cmd_name}", + "source_file": source_file, + }) + + return commands + + +def parse_subcommands_from_file(warp_internal: Path, filename: str) -> list[str]: + """Parse subcommand names from a CLI command file (e.g., agent.rs).""" + filepath = warp_internal / "warp_cli" / "src" / filename + if not filepath.exists(): + return [] + + content = filepath.read_text() + subcommands = [] + + # Find enum variants that represent subcommands + for match in re.finditer(r"///\s*(.+?)\n\s*(?:#\[.*?\]\s*\n\s*)*([A-Z]\w+)", content): + subcommands.append(match.group(2)) + + return subcommands + + +def audit_cli(warp_internal: Path, docs_root: Path, surface_map: dict, + docs_text: dict[str, str]) -> list[dict]: + """Audit CLI command coverage in docs.""" + commands = parse_cli_commands(warp_internal) + cli_to_doc = surface_map.get("cli_to_doc", {}) + + # Read all CLI docs content + cli_docs_dir = docs_root / "reference" / "cli" + cli_docs_text = {} + if cli_docs_dir.exists(): + for f in find_markdown_files(cli_docs_dir): + try: + cli_docs_text[str(f)] = f.read_text(encoding="utf-8").lower() + except Exception: + pass + + findings = [] + for cmd in commands: + cmd_str = cmd["command"] + + # Check surface map + if cmd_str in cli_to_doc: + doc_path = cli_to_doc[cmd_str] + if (docs_root.parent / doc_path).exists(): + continue # Mapped and exists + + # Search CLI docs for the command name + cmd_name = cmd_str.split()[-1] # e.g., "agent" from "oz agent" + found = False + for content in cli_docs_text.values(): + if cmd_name in content: + found = True + break + + if not found: + findings.append({ + "command": cmd_str, + "source_file": cmd.get("source_file"), + "severity": "high", + "reason": f"CLI command '{cmd_str}' not mentioned in CLI reference docs", + }) + + return findings + +# --------------------------------------------------------------------------- +# Audit 3: API endpoint coverage +# --------------------------------------------------------------------------- + +def parse_api_routes(warp_server: Path) -> list[dict]: + """Parse API route definitions from router.go.""" + router_go = warp_server / "router" / "router.go" + if not router_go.exists(): + return [] + + content = router_go.read_text() + routes = [] + + # Match patterns like: + # r.GET("/api/v1/agent/runs", ...) + # r.POST("/api/v1/agent/run", ...) + for match in re.finditer( + r'\.\s*(GET|POST|PUT|DELETE|PATCH)\s*\(\s*"(/[^"]+)"', + content, + ): + method = match.group(1) + path = match.group(2) + # Skip internal/debug endpoints + if "/internal/" in path or "/debug/" in path: + continue + routes.append({ + "method": method, + "path": path, + "route": f"{method} {path}", + }) + + return routes + + +def audit_api(warp_server: Path, docs_root: Path, surface_map: dict, + docs_text: dict[str, str]) -> list[dict]: + """Audit API endpoint coverage in docs.""" + routes = parse_api_routes(warp_server) + api_to_doc = surface_map.get("api_to_doc", {}) + + # Read API docs + api_docs_dir = docs_root / "reference" / "api-and-sdk" + api_docs_text = {} + if api_docs_dir.exists(): + for f in find_markdown_files(api_docs_dir): + try: + api_docs_text[str(f)] = f.read_text(encoding="utf-8").lower() + except Exception: + pass + + # Also check OpenAPI spec + openapi_path = docs_root / "developers" / "agent-api-openapi.yaml" + openapi_text = "" + if openapi_path.exists(): + try: + openapi_text = openapi_path.read_text(encoding="utf-8").lower() + except Exception: + pass + + findings = [] + for route in routes: + route_str = route["route"] + + # Check surface map + if route_str in api_to_doc: + continue + + # Search API docs and OpenAPI spec for the path + path_lower = route["path"].lower() + found = False + for content in api_docs_text.values(): + if path_lower in content: + found = True + break + if not found and path_lower in openapi_text: + found = True + + if not found: + # Determine handler file + handler_file = None + handlers_dir = warp_server / "router" / "handlers" + if handlers_dir.exists(): + # Try to match based on path segments + path_parts = [p for p in route["path"].split("/") if p and p != "api" and p != "v1"] + if path_parts: + for f in handlers_dir.iterdir(): + if f.suffix == ".go" and path_parts[0] in f.name: + handler_file = f"router/handlers/{f.name}" + break + + findings.append({ + "route": route_str, + "handler_file": handler_file, + "severity": "medium", + "reason": f"API endpoint '{route_str}' not documented in API reference", + }) + + return findings + +# --------------------------------------------------------------------------- +# Audit 4: Docs staleness +# --------------------------------------------------------------------------- + +def audit_staleness(warp_internal: Path, docs_root: Path, + docs_text: dict[str, str], + stale_terms_path: Path = STALE_TERMS_PATH) -> list[dict]: + """Check for docs referencing features that no longer exist in code.""" + # Get current feature flags for comparison + current_flags = set(parse_feature_flags(warp_internal)) + current_flags_lower = {f.lower() for f in current_flags} + + # Load stale terms from external reference file + stale_terms = parse_stale_terms(stale_terms_path) + + findings = [] + for doc_path, content in docs_text.items(): + stale_found = [] + for term, reason in stale_terms: + if term in content: + stale_found.append({"term": term, "reason": reason}) + + if stale_found: + findings.append({ + "doc_path": doc_path, + "stale_terms": stale_found, + "severity": "low", + "reason": "Doc contains potentially outdated terminology", + }) + + return findings + +# --------------------------------------------------------------------------- +# Report generation +# --------------------------------------------------------------------------- + +def generate_report(features: list, cli: list, api: list, staleness: list) -> dict: + """Assemble the full audit report.""" + total = len(features) + len(cli) + len(api) + len(staleness) + return { + "summary": { + "total_gaps": total, + "by_category": { + "undocumented_features": len(features), + "undocumented_cli_commands": len(cli), + "undocumented_api_endpoints": len(api), + "potentially_stale_docs": len(staleness), + }, + }, + "undocumented_features": features, + "undocumented_cli_commands": cli, + "undocumented_api_endpoints": api, + "potentially_stale_docs": staleness, + } + + +def print_report(report: dict) -> None: + """Print a human-readable report to stdout.""" + summary = report["summary"] + print("=" * 60) + print("MISSING DOCS AUDIT REPORT") + print("=" * 60) + print(f"Total gaps found: {summary['total_gaps']}") + for category, count in summary["by_category"].items(): + print(f" {category}: {count}") + print() + + severity_order = {"high": 0, "medium": 1, "low": 2} + + if report["undocumented_features"]: + print("-" * 60) + print(f"UNDOCUMENTED FEATURES ({len(report['undocumented_features'])})") + print("-" * 60) + items = sorted(report["undocumented_features"], + key=lambda x: severity_order.get(x.get("severity", "low"), 3)) + for item in items: + sev = item.get("severity", "?").upper() + print(f"\n [{sev}] {item['flag']}") + print(f" Reason: {item['reason']}") + if item.get("suggested_doc_path"): + print(f" Suggested: {item['suggested_doc_path']}") + print(f" Search terms: {', '.join(item['search_terms'][:3])}") + + if report["undocumented_cli_commands"]: + print() + print("-" * 60) + print(f"UNDOCUMENTED CLI COMMANDS ({len(report['undocumented_cli_commands'])})") + print("-" * 60) + for item in report["undocumented_cli_commands"]: + sev = item.get("severity", "?").upper() + print(f"\n [{sev}] {item['command']}") + print(f" Reason: {item['reason']}") + if item.get("source_file"): + print(f" Source: {item['source_file']}") + + if report["undocumented_api_endpoints"]: + print() + print("-" * 60) + print(f"UNDOCUMENTED API ENDPOINTS ({len(report['undocumented_api_endpoints'])})") + print("-" * 60) + for item in report["undocumented_api_endpoints"]: + sev = item.get("severity", "?").upper() + print(f"\n [{sev}] {item['route']}") + print(f" Reason: {item['reason']}") + if item.get("handler_file"): + print(f" Handler: {item['handler_file']}") + + if report["potentially_stale_docs"]: + print() + print("-" * 60) + print(f"POTENTIALLY STALE DOCS ({len(report['potentially_stale_docs'])})") + print("-" * 60) + for item in report["potentially_stale_docs"]: + sev = item.get("severity", "?").upper() + print(f"\n [{sev}] {item['doc_path']}") + for t in item.get("stale_terms", []): + print(f" - \"{t['term']}\": {t['reason']}") + + print() + print("=" * 60) + +# --------------------------------------------------------------------------- +# Main +# --------------------------------------------------------------------------- + +def main(): + parser = argparse.ArgumentParser( + description="Audit Warp documentation coverage against code surfaces" + ) + parser.add_argument( + "--warp-internal", + help="Path to warp-internal repo (auto-detected if not provided)", + ) + parser.add_argument( + "--warp-server", + help="Path to warp-server repo (auto-detected if not provided)", + ) + parser.add_argument( + "--output", "-o", + help="Save JSON report to file", + ) + parser.add_argument( + "--category", + choices=["features", "cli", "api", "staleness"], + help="Run only a specific audit category", + ) + parser.add_argument( + "--severity", + choices=["high", "medium", "low"], + help="Filter results by minimum severity", + ) + args = parser.parse_args() + + # Find repos + docs_root = SKILL_DIR.parent.parent.parent # .warp/skills/missing_docs -> docs root + docs_root = docs_root / "docs" + + if not docs_root.exists(): + print(f"Error: docs directory not found at {docs_root}", file=sys.stderr) + sys.exit(1) + + warp_internal = find_repo("warp-internal", args.warp_internal, docs_root) + warp_server = find_repo("warp-server", args.warp_server, docs_root) + + # Parse surface map + surface_map = parse_surface_map(SURFACE_MAP_PATH) + + # Read all docs + print("Scanning documentation...", file=sys.stderr) + docs_text = read_all_docs_text(docs_root) + print(f" Found {len(docs_text)} markdown files", file=sys.stderr) + + # Run audits + features_findings = [] + cli_findings = [] + api_findings = [] + staleness_findings = [] + + if warp_internal: + print(f"Using warp-internal: {warp_internal}", file=sys.stderr) + if args.category in (None, "features"): + print("Running feature flag coverage audit...", file=sys.stderr) + features_findings = audit_features(warp_internal, docs_root, surface_map, docs_text) + + if args.category in (None, "cli"): + print("Running CLI command coverage audit...", file=sys.stderr) + cli_findings = audit_cli(warp_internal, docs_root, surface_map, docs_text) + + if args.category in (None, "staleness"): + print("Running docs staleness audit...", file=sys.stderr) + staleness_findings = audit_staleness(warp_internal, docs_root, docs_text) + else: + print("Warning: warp-internal not found, skipping feature/CLI/staleness audits", + file=sys.stderr) + + if warp_server: + print(f"Using warp-server: {warp_server}", file=sys.stderr) + if args.category in (None, "api"): + print("Running API endpoint coverage audit...", file=sys.stderr) + api_findings = audit_api(warp_server, docs_root, surface_map, docs_text) + else: + print("Warning: warp-server not found, skipping API audit", file=sys.stderr) + + # Filter by severity + if args.severity: + severity_order = {"high": 0, "medium": 1, "low": 2} + min_severity = severity_order[args.severity] + features_findings = [f for f in features_findings + if severity_order.get(f.get("severity"), 3) <= min_severity] + cli_findings = [f for f in cli_findings + if severity_order.get(f.get("severity"), 3) <= min_severity] + api_findings = [f for f in api_findings + if severity_order.get(f.get("severity"), 3) <= min_severity] + staleness_findings = [f for f in staleness_findings + if severity_order.get(f.get("severity"), 3) <= min_severity] + + # Generate report + report = generate_report(features_findings, cli_findings, api_findings, staleness_findings) + + # Output + print_report(report) + + if args.output: + output_path = Path(args.output) + output_path.write_text(json.dumps(report, indent=2)) + print(f"\nJSON report saved to {output_path}", file=sys.stderr) + + +if __name__ == "__main__": + main() diff --git a/.warp/skills/review-docs-pr/SKILL.md b/.warp/skills/review-docs-pr/SKILL.md new file mode 100644 index 0000000..b96593f --- /dev/null +++ b/.warp/skills/review-docs-pr/SKILL.md @@ -0,0 +1,106 @@ +--- +name: review-docs-pr +description: Reviews documentation pull requests for the Warp docs repository. Checks for broken links, style guide compliance, content quality, and Astro Starlight structure. Use when reviewing documentation PRs or when you need to provide feedback on markdown documentation changes. +--- + +# Review Documentation PR + +This skill reviews documentation pull requests for the Warp docs repository. + +## Usage + +Use this skill when reviewing documentation changes in PRs. The skill will: +- Check for potential broken links +- Verify style guide compliance +- Review content quality +- Check Astro Starlight structure integrity + +## Review Instructions + +Review this documentation PR for the docs repository. + +Focus on: +1. **Broken links**: Check for potential broken internal links (relative paths, cross-space links). You can run the broken link checker at `python3 .warp/skills/check_for_broken_links/check_links.py --internal-only` if helpful. +2. **Style guide compliance**: Reference `AGENTS.md` for documentation standards (voice, formatting, terminology). +3. **Content quality**: Check for clarity, accuracy, proper frontmatter, and appropriate use of headers/lists. +4. **Code snippets**: Verify that any code examples, commands, or configuration snippets are correct and will work as documented. If you're unsure about technical details, use the `answer_question` skill to verify against the docs or search the source code. +5. **Astro Starlight structure**: Verify astro.config.mjs (sidebar config) updates if files were moved/renamed, and that redirects are added to vercel.json (redirects) when needed. + +Provide actionable, constructive feedback. Focus on documentation quality issues, not code bugs. + +### Severity Labels (Required) + +Every comment body MUST begin with one of: +- `🚨 [CRITICAL]` — Broken links, incorrect commands/code, factually wrong information that could confuse users +- `⚠️ [IMPORTANT]` — Style guide violations, missing redirects, structural issues +- `💡 [SUGGESTION]` — Improvements to clarity, wording, or structure +- `🧹 [NIT]` — Typos, minor formatting (ONLY if providing a suggestion block) + +### Using answer_question for verification + +If you encounter: +- Unclear or potentially incorrect technical information +- Commands or code examples you want to verify +- Feature descriptions that seem outdated or inaccurate +- Questions about how something actually works + +Use the `answer_question` skill to search the documentation and source code for authoritative information before making your review comment. + +## Output Format + +Create a `review.json` file with the following structure: + +```json +{ + "summary": "High-level overview of the changes and verdict", + "comments": [ + { + "path": "path/to/file.md", + "line": 42, + "side": "RIGHT", + "body": "Your feedback here" + } + ] +} +``` + +### Summary Requirements + +The summary should: +- Start with a brief (2-3 sentence) overview of what the PR changes and your assessment +- Include issue counts: "Found: X critical, Y important, Z suggestions, N nits" +- End with final recommendation: "Approve", "Approve with nits", or "Request changes" + +Keep the tone helpful and constructive. The summary can mention positive aspects (e.g., "good improvements to clarity") alongside concerns. + +### Comment Format + +Each comment should: +- Reference a specific line in a changed file +- Be actionable and constructive +- Use `side: "RIGHT"` for new/added lines (the new content after changes) - use this in most cases +- Use `side: "LEFT"` only when commenting on deleted/old lines (the content before changes) +- Focus on the diff, not unchanged code +- Keep comment spans ≤10 lines (i.e., `line - start_line <= 10`) for easier review +- Use single-line comments for specific issues (typos, broken links); use multi-line spans when the issue or suggestion requires multiple lines of context + +#### Using GitHub Suggestion Syntax + +When you have a specific fix or improvement, use GitHub's suggestion syntax in your comment body. This allows the author to apply your suggestion with one click. + +Use suggestions for: +- Fixing typos or grammar +- Correcting commands or code snippets +- Improving wording or phrasing +- Fixing broken links +- Correcting terminology to match the style guide + +If the changes look good with no major issues, indicate approval in the summary. For minor issues, suggest improvements but still recommend approval. Only request changes if there are significant problems that need to be fixed before merge. + +## Validation + +After creating `review.json`: +- Validate JSON with `jq . review.json` - if this fails, fix the JSON syntax and try again +- Verify all paths exist in the PR diff and match the changed files +- Check that line numbers are within the changed files and reference lines that were actually modified +- Ensure comment spans don't exceed 10 lines diff --git a/.warp/skills/style_lint/SKILL.md b/.warp/skills/style_lint/SKILL.md new file mode 100644 index 0000000..f2550d9 --- /dev/null +++ b/.warp/skills/style_lint/SKILL.md @@ -0,0 +1,79 @@ +--- +name: style_lint +description: Scan Warp Astro Starlight documentation for style guide violations including formatting issues (Settings path format, UI element format, header case, missing frontmatter, image alt text, callout syntax) and terminology issues (product name casing, Oz terms to avoid, deprecated terms). Run with --changed for PR workflows or --all for periodic audits. Optionally auto-fix high-confidence issues with --fix. +--- + +# Style Lint + +Scan Warp Astro Starlight documentation for formatting and terminology issues defined in the style guide (`AGENTS.md`). + +## Running the check + +From the docs repo root: + +```bash +python3 .warp/skills/style_lint/style_lint.py +``` + +### Options + +- `--all`: Scan all markdown files in `docs/` (default) +- `--changed`: Scan only files changed in the current branch (fast, for PR workflows) +- `--fix`: Auto-fix high-confidence issues (optional, off by default) +- `--create-pr`: Create a branch and PR with auto-fixes (requires `gh` CLI, implies `--fix`) +- `--output FILE`: Save results to JSON file +- `--slack-notify`: Send results to Slack (only sends when issues are found; requires `SLACK_BOT_TOKEN` and `SLACK_CHANNEL_ID` env vars) +- `--slack-channel ID`: Override the default Slack channel + +### Quick check on changed files: + +```bash +python3 .warp/skills/style_lint/style_lint.py --changed +``` + +### Full audit with auto-fix and PR: + +```bash +python3 .warp/skills/style_lint/style_lint.py --all --fix --create-pr +``` + +## What it checks + +### Formatting checks + +- **Settings paths**: Backtick-wrapped Settings paths (`` `Settings > X` ``) → should be per-segment bold (**Settings** > **X**) +- **UI elements after action verbs**: `click \`X\`` → should be `click **X**` +- **Header case**: Title Case in H2/H3/H4 headers (should be sentence case, with exceptions for proper feature names) +- **Missing frontmatter**: Pages without YAML `description` field +- **Image alt text**: `<img>` or `<figure>` without alt text or with generic alt text ("screenshot", "image") +- **Callout syntax**: Leftover GitBook `{% hint %}` tags that should be migrated to Starlight `:::note` / `:::caution` / `:::danger` asides +- **List format**: Bulleted feature/capability lists missing the bold term + dash pattern (report only, never auto-fixed) + +### Terminology checks + +- **Product name casing**: "Warp Terminal" (→ "Warp"), "agent mode" (→ "Agent Mode"), "warp drive" (→ "Warp Drive"), "codebase context" (→ "Codebase Context"), "agent management panel" (→ "Agent Management Panel") +- **Oz terms to avoid**: "Ozzies", "Deploying an Oz", "The Oz Agent", "Oz is running", "AI agents" +- **Deprecated terminology**: "whitelist" (→ "allowlist"), "blacklist"/"blocklist" (→ "denylist") +- **External product names**: "Github" (→ "GitHub"), "github actions" (→ "GitHub Actions"), "MacOS" (→ "macOS"), "A.I." (→ "AI") +- **Unrecognized terms** (warning): Bolded terms that look like product names but aren't in `terminology.md`. Flags candidates for glossary addition — not errors, just suggestions. + +## Auto-fix behavior + +When run with `--fix`: +- **High-confidence fixes applied automatically**: Settings path format, UI element format, product name casing, external product name casing +- **Low-confidence issues reported but not auto-fixed**: list format, header case (due to feature name exceptions), ambiguous terminology + +## Relationship to validate_ui_refs + +This skill checks broader formatting and terminology. The `validate_ui_refs` skill validates UI paths and Command Palette names against the warp-internal codebase. They complement each other with no overlap. Both can run in scheduled Oz agent workflows. + +## Dependencies + +Requires Python 3.7+. Optional: `requests` (for Slack notifications), `gh` CLI (for PR creation). + +## Cloud agent / scheduling + +For scheduled Oz cloud agent runs: +1. Configure the environment with the docs repo +2. Set the `SLACK_BOT_TOKEN` secret in the environment (for `--slack-notify`) +3. Run: `python3 .warp/skills/style_lint/style_lint.py --all --fix --create-pr --slack-notify` diff --git a/.warp/skills/style_lint/style_lint.py b/.warp/skills/style_lint/style_lint.py new file mode 100644 index 0000000..e9efa5c --- /dev/null +++ b/.warp/skills/style_lint/style_lint.py @@ -0,0 +1,726 @@ +#!/usr/bin/env python3 +"""Style lint for Warp Astro Starlight documentation. + +Checks markdown files for formatting and terminology issues defined in the +AGENTS.md style guide. Supports scanning all files or only changed files, +optional auto-fix, PR creation, and Slack notifications. + +Usage: + python3 style_lint.py [--all|--changed] [--fix] [--create-pr] [--output FILE] + [--slack-notify] [--slack-channel ID] +""" + +import argparse +import json +import os +import re +import subprocess +import sys +from dataclasses import dataclass, field +from pathlib import Path +from typing import List, Optional, Tuple + +# --------------------------------------------------------------------------- +# Configuration +# --------------------------------------------------------------------------- + +DOCS_ROOT = Path("docs") +CHANGELOG_DIR = DOCS_ROOT / "changelog" +EXCLUDED_DIRS = {"_book", "node_modules", ".docs"} + +# Feature names that are correctly Title Case (exceptions to sentence-case rule) +PROPER_FEATURE_NAMES = { + "Admin Panel", "Agent Management Panel", "Agent Mode", "Agent Profiles", + "Ambient Agents", "Auto-detection Mode", "Cloud Agent Credits", + "Codebase Context", "Code Review", "Command Palette", "Global Rules", + "Oz CLI", "Oz Platform", "Project Rules", "Slash Commands", + "Terminal Mode", "Universal Input", "Warp Drive", "Warp Platform", +} + +# Terminology: wrong → right (case-sensitive checks) +PRODUCT_CASING = { + "Warp Terminal": ("Warp", "Use 'Warp' unless specifically distinguishing from Oz"), + "agent mode": ("Agent Mode", "Capitalize as a feature name"), + "agent management panel": ("Agent Management Panel", "Capitalize as a UI surface name"), + "warp drive": ("Warp Drive", "Capitalize as a feature name"), + "codebase context": ("Codebase Context", "Capitalize as a feature name"), + "command palette": ("Command Palette", "Capitalize as a feature name"), + "admin panel": ("Admin Panel", "Capitalize as a feature name"), +} + +# External product names (case-sensitive) +EXTERNAL_CASING = { + "Github": ("GitHub", "Capitalize the H"), + "github actions": ("GitHub Actions", "Capitalize both words"), + "MacOS": ("macOS", "Lowercase m"), + "Mac OS": ("macOS", "Use 'macOS'"), + "A.I.": ("AI", "Use 'AI' not 'A.I.'"), +} + +# Deprecated terminology (case-insensitive) +DEPRECATED_TERMS = [ + (r"\bwhitelist\b", "Use 'allowlist'"), + (r"\bblacklist\b", "Use 'denylist'"), + (r"\bblocklist\b", "Use 'denylist'"), +] + +# Oz terms to avoid (case-insensitive patterns) +OZ_TERMS_TO_AVOID = [ + (r"\bOzzies\b", "Use 'Oz agents', 'instances', or 'Oz subagents'"), + (r"\bDeploying an Oz\b", "Use 'Deploying an Oz agent'"), + (r"\bThe Oz Agent\b", "Use 'An Oz agent' or 'A parent Oz agent'"), + (r"\bOz is running\b", "Use 'An Oz agent is running' or 'A run is in progress'"), + (r"\bAI agents?\b", "Use 'agents' (the 'AI' prefix is redundant)"), +] + +# Action verbs that precede UI elements (should be bold, not backtick) +UI_ACTION_VERBS = r"(?:click|select|toggle|enable|disable|choose|check|uncheck|expand|collapse|open|close|tap)" + +DEFAULT_SLACK_CHANNEL = os.environ.get("SLACK_CHANNEL_ID", "") + +TERMINOLOGY_FILE = Path(".warp/references/terminology.md") + +# Common bolded words that are NOT product terms (false positive suppression) +COMMON_BOLD_WORDS = { + # General emphasis words + "Note", "Important", "Warning", "Example", "Examples", "Step", "Steps", + "Tip", "Tips", "Required", "Optional", "Default", "Summary", "Overview", + "Prerequisites", "Prerequisite", "Result", "Results", "Outcome", + "Next", "Previous", "See", "Related", "Key", "Keys", "Value", "Values", + "True", "False", "Yes", "No", "None", "All", "Any", "New", "Old", + "Name", "Type", "Description", "Status", "Action", "Actions", + "Bold", "Italic", "What", "Why", "How", "When", "Where", "Who", + "Good", "Bad", "Do", "Don't", "Use", "Avoid", "Before", "After", + "Phase", "Option", "Options", "Feature", "Features", "Setup", + "Structure", "Rules", "Template", "Existing", "Heading", + "IMPORTANT", "PHASE", "COMPLETED", + # UI labels and status words commonly bolded in docs + "Start", "Stop", "Save", "Cancel", "Delete", "Edit", "Add", "Remove", + "Enable", "Disable", "Create", "Update", "Submit", "Apply", "Confirm", + "Back", "Done", "Close", "Open", "Run", "Test", "Copy", "Paste", + "Personal", "Global", "Team", "Custom", "Manage", "View", "Preview", + "Active", "Inactive", "Enabled", "Disabled", "Experimental", "Beta", + "Failed", "Success", "Error", "Pending", "Complete", "Completed", + "General", "Advanced", "Basic", "Pro", "Free", "Enterprise", + "Configuration", "Preferences", "References", "Visibility", + "Execution", "Task", "Steer", "Templates", "Knowledge", + "Docker", "Sentry", "Puppeteer", # Third-party tools commonly mentioned +} + + +@dataclass +class Issue: + file: str + line: int + check: str + message: str + severity: str # "error" or "warning" + fixable: bool = False + fix_from: str = "" + fix_to: str = "" + + +@dataclass +class Report: + files_scanned: int = 0 + issues: List[Issue] = field(default_factory=list) + fixes_applied: int = 0 + + +# --------------------------------------------------------------------------- +# File discovery +# --------------------------------------------------------------------------- + +def find_all_md_files() -> List[Path]: + """Find all markdown files in docs/, excluding build artifacts and changelog.""" + files = [] + for f in DOCS_ROOT.rglob("*.md"): + if any(part in EXCLUDED_DIRS for part in f.parts): + continue + # Exclude changelog (historical record) + if f.is_relative_to(CHANGELOG_DIR): + continue + files.append(f) + return sorted(files) + + +def find_changed_md_files() -> List[Path]: + """Find markdown files changed in the current branch vs main.""" + try: + result = subprocess.run( + ["git", "diff", "--name-only", "origin/main...HEAD", "--", "docs/"], + capture_output=True, text=True, check=True, + ) + files = [] + for line in result.stdout.strip().split("\n"): + if line.endswith(".md") and os.path.exists(line): + p = Path(line) + if not any(part in EXCLUDED_DIRS for part in p.parts): + files.append(p) + return sorted(files) + except subprocess.CalledProcessError: + print("Warning: could not determine changed files. Falling back to --all.") + return find_all_md_files() + + +# --------------------------------------------------------------------------- +# Checks +# --------------------------------------------------------------------------- + +def check_frontmatter(content: str, filepath: str) -> List[Issue]: + """Check for missing or empty frontmatter description.""" + issues = [] + if not content.startswith("---"): + issues.append(Issue(filepath, 1, "frontmatter", "Missing YAML frontmatter", "error")) + return issues + end = content.find("---", 3) + if end == -1: + issues.append(Issue(filepath, 1, "frontmatter", "Malformed YAML frontmatter (no closing ---)", "error")) + return issues + fm = content[3:end] + if "description:" not in fm: + issues.append(Issue(filepath, 1, "frontmatter", "Frontmatter missing 'description' field", "error")) + return issues + + +def check_settings_paths(lines: List[str], filepath: str) -> List[Issue]: + """Detect backtick-wrapped Settings paths that should be bold per-segment.""" + issues = [] + pattern = re.compile(r"`(Settings\s*>\s*[^`]+)`") + for i, line in enumerate(lines, 1): + for m in pattern.finditer(line): + original = m.group(0) + inner = m.group(1) + # Build the bold version + segments = [s.strip() for s in inner.split(">")] + bold_version = " > ".join(f"**{s}**" for s in segments) + issues.append(Issue( + filepath, i, "settings-path", + f"Settings path in backticks: {original} → {bold_version}", + "warning", fixable=True, fix_from=original, fix_to=bold_version, + )) + return issues + + +def check_ui_element_backticks(lines: List[str], filepath: str) -> List[Issue]: + """Detect UI elements in backticks after action verbs (should be bold).""" + issues = [] + pattern = re.compile( + rf"(?:^|\s){UI_ACTION_VERBS}(?:\s+(?:on|the))?\s+`([^`]+)`", + re.IGNORECASE, + ) + for i, line in enumerate(lines, 1): + for m in pattern.finditer(line): + backtick_text = m.group(1) + # Skip things that look like code (paths, flags, CamelCase identifiers) + if "/" in backtick_text or backtick_text.startswith("-") or backtick_text.startswith("$"): + continue + issues.append(Issue( + filepath, i, "ui-backtick", + f"UI element in backticks after action verb: `{backtick_text}` → **{backtick_text}**", + "warning", fixable=True, + fix_from=f"`{backtick_text}`", fix_to=f"**{backtick_text}**", + )) + return issues + + +def _to_sentence_case(text: str) -> str: + """Convert header text to sentence case, preserving proper feature names and acronyms.""" + skip_words = {"I", "A", "API", "CLI", "SDK", "SSH", "UI", "URL", "PR", "CI", "CD"} + words = text.split() + + # Mark word positions that are part of a complete proper feature name match. + # Only protect words when the full multi-word name appears as a sequence. + protected = [False] * len(words) + for fn in PROPER_FEATURE_NAMES: + fn_words = fn.split() + for start in range(len(words) - len(fn_words) + 1): + if all(words[start + j].lower() == fn_words[j].lower() for j in range(len(fn_words))): + for j in range(len(fn_words)): + protected[start + j] = True + + result = [] + for idx, w in enumerate(words): + if idx == 0 or protected[idx]: + result.append(w) + continue + clean = re.sub(r"[^a-zA-Z]", "", w) + if not clean or clean in skip_words or len(clean) <= 1: + result.append(w) + continue + # Preserve all-caps words (acronyms not in skip_words) + if clean.isupper() and len(clean) > 1: + result.append(w) + continue + # Lowercase the word + result.append(w.lower()) + return " ".join(result) + + +def check_header_case(lines: List[str], filepath: str) -> List[Issue]: + """Detect Title Case in H2-H4 headers (should be sentence case).""" + issues = [] + header_pattern = re.compile(r"^(#{2,4})\s+(.+)$") + for i, line in enumerate(lines, 1): + m = header_pattern.match(line) + if not m: + continue + hashes = m.group(1) + text = m.group(2).strip() + words = text.split() + if len(words) < 2: + continue + # Count capitalized non-first words (excluding proper feature names, short words) + skip_words = {"I", "A", "API", "CLI", "SDK", "SSH", "UI", "URL", "PR", "CI", "CD"} + title_case_count = 0 + for w in words[1:]: + clean = re.sub(r"[^a-zA-Z]", "", w) + if not clean or clean in skip_words or len(clean) <= 2: + continue + # Check if it's part of a known feature name + is_feature_name = any(clean in fn for fn in PROPER_FEATURE_NAMES) + if is_feature_name: + continue + if clean[0].isupper() and clean[1:].islower(): + title_case_count += 1 + if title_case_count >= 2: + fixed_text = _to_sentence_case(text) + original_line = f"{hashes} {text}" + fixed_line = f"{hashes} {fixed_text}" + issues.append(Issue( + filepath, i, "header-case", + f"Possible Title Case header (should be sentence case): \"{text}\" → \"{fixed_text}\"", + "warning", fixable=True, fix_from=original_line, fix_to=fixed_line, + )) + return issues + + +def check_image_alt_text(lines: List[str], filepath: str) -> List[Issue]: + """Detect images without alt text or with generic alt text.""" + issues = [] + img_pattern = re.compile(r'<img\s[^>]*alt="([^"]*)"', re.IGNORECASE) + img_no_alt = re.compile(r"<img\s(?:(?!alt=)[^>])*>", re.IGNORECASE) + generic_alts = {"screenshot", "image", "screen", "pic", "photo", ""} + + for i, line in enumerate(lines, 1): + for m in img_pattern.finditer(line): + alt = m.group(1).strip().lower() + if alt in generic_alts: + issues.append(Issue( + filepath, i, "alt-text", + f"Generic or empty alt text: alt=\"{m.group(1)}\"", + "warning", + )) + for m in img_no_alt.finditer(line): + if "alt=" not in m.group(0).lower(): + issues.append(Issue( + filepath, i, "alt-text", + "Image tag missing alt attribute", + "warning", + )) + return issues + + +def check_callout_syntax(lines: List[str], filepath: str) -> List[Issue]: + """Check for malformed hint/callout syntax.""" + issues = [] + valid_styles = {"info", "warning", "danger", "success"} + hint_open = re.compile(r'{%\s*hint\s+style="([^"]*)"') + hint_close = re.compile(r"{%\s*endhint\s*%}") + + open_count = 0 + for i, line in enumerate(lines, 1): + for m in hint_open.finditer(line): + style = m.group(1) + if style not in valid_styles: + issues.append(Issue( + filepath, i, "callout", + f"Invalid hint style: \"{style}\". Valid styles: {', '.join(sorted(valid_styles))}", + "error", + )) + open_count += 1 + for _ in hint_close.finditer(line): + open_count -= 1 + + if open_count > 0: + issues.append(Issue( + filepath, len(lines), "callout", + f"{open_count} unclosed {{%% hint %%}} tag(s) — missing {{%% endhint %%}}", + "error", + )) + return issues + + +def check_product_casing(lines: List[str], filepath: str) -> List[Issue]: + """Check for incorrect product name casing.""" + issues = [] + for i, line in enumerate(lines, 1): + # Skip code blocks + if line.strip().startswith("```") or line.strip().startswith("`"): + continue + for wrong, (right, note) in PRODUCT_CASING.items(): + # Case-sensitive search + idx = line.find(wrong) + while idx != -1: + issues.append(Issue( + filepath, i, "product-casing", + f"\"{wrong}\" → \"{right}\" ({note})", + "warning", fixable=True, fix_from=wrong, fix_to=right, + )) + idx = line.find(wrong, idx + len(wrong)) + + for wrong, (right, note) in EXTERNAL_CASING.items(): + idx = line.find(wrong) + while idx != -1: + issues.append(Issue( + filepath, i, "external-casing", + f"\"{wrong}\" → \"{right}\" ({note})", + "warning", fixable=True, fix_from=wrong, fix_to=right, + )) + idx = line.find(wrong, idx + len(wrong)) + return issues + + +def check_oz_terms(lines: List[str], filepath: str) -> List[Issue]: + """Check for Oz terms to avoid.""" + issues = [] + for i, line in enumerate(lines, 1): + if line.strip().startswith("```") or line.strip().startswith("`"): + continue + for pattern, suggestion in OZ_TERMS_TO_AVOID: + for m in re.finditer(pattern, line, re.IGNORECASE): + issues.append(Issue( + filepath, i, "oz-term", + f"Avoid \"{m.group(0)}\" → {suggestion}", + "warning", + )) + return issues + + +def check_deprecated_terms(lines: List[str], filepath: str) -> List[Issue]: + """Check for deprecated terminology (whitelist/blacklist/blocklist).""" + issues = [] + for i, line in enumerate(lines, 1): + if line.strip().startswith("```") or line.strip().startswith("`"): + continue + for pattern, suggestion in DEPRECATED_TERMS: + for m in re.finditer(pattern, line, re.IGNORECASE): + issues.append(Issue( + filepath, i, "deprecated-term", + f"Avoid \"{m.group(0)}\" → {suggestion}", + "warning", + )) + return issues + + +def load_glossary_terms() -> set: + """Load known term names from terminology.md.""" + terms = set() + if not TERMINOLOGY_FILE.exists(): + return terms + content = TERMINOLOGY_FILE.read_text(encoding="utf-8") + # Match bolded terms: - **Term** or - **Term** / **Variant** + for m in re.finditer(r"- \*\*([^*]+)\*\*", content): + raw = m.group(1) + # Handle "Term / Variant" entries + for part in raw.split("/"): + terms.add(part.strip()) + # Also add proper feature names + terms.update(PROPER_FEATURE_NAMES) + return terms + + +def check_unrecognized_terms(lines: List[str], filepath: str, glossary: set) -> List[Issue]: + """Flag bolded terms that look like product names but aren't in the glossary. + + Reports as warnings — these are candidates for glossary addition, not errors. + Only flags short, Title-Case terms that resemble product or feature names. + """ + issues = [] + if not glossary: + return issues + + bold_pattern = re.compile(r"\*\*([^*]+)\*\*") + in_code_block = False + seen_terms: set = set() # Deduplicate within a file + + for i, line in enumerate(lines, 1): + # Track code block boundaries + if line.strip().startswith("```"): + in_code_block = not in_code_block + continue + if in_code_block: + continue + + # Skip list-format definitions (bold term + dash/colon pattern) + # e.g., "- **Term** — definition" or "**Term**: description" + if re.match(r"\s*[-*]\s+\*\*", line) and ("—" in line or ": " in line.split("**")[-1][:5] if "**" in line else False): + continue + + for m in bold_pattern.finditer(line): + term = m.group(1).strip() + + # --- Strict filters to only catch product/feature names --- + + # Skip if already seen in this file + if term in seen_terms: + continue + + # Skip common false positives + if term in COMMON_BOLD_WORDS: + continue + + # Max 3 words — product names are short + words = term.split() + if len(words) > 3: + continue + + # Must be Title Case or specific casing pattern (not sentence-case phrases) + # At least the first word must be capitalized, and for multi-word terms + # at least 2 words should be capitalized + if len(words) == 1: + # Single word: must start uppercase and not be all-caps (acronym) + if not words[0][0].isupper() or (words[0].isupper() and len(words[0]) <= 5): + continue + else: + # Multi-word: need at least 2 capitalized words (Title Case signal) + cap_count = sum(1 for w in words if w[0].isupper() and len(w) > 1) + if cap_count < 2: + continue + + # Skip very short terms + if len(term) < 3: + continue + + # Skip things that look like code (paths, flags, camelCase) + if "/" in term or term.startswith("-") or term.startswith("$"): + continue + if re.match(r"^[a-z]+[A-Z]", term): # camelCase + continue + + # Skip terms containing punctuation that product names don't have + if any(c in term for c in ".,;:!?()[]{}\"'"): + continue + + # Skip UI action patterns ("Click **Save**" — Save is a button, not a term) + prefix = line[:m.start()].rstrip() + if re.search(rf"{UI_ACTION_VERBS}\s*$", prefix, re.IGNORECASE): + continue + + # Check against glossary + if term not in glossary: + seen_terms.add(term) + issues.append(Issue( + filepath, i, "unrecognized-term", + f"Bolded term not in glossary: \"{term}\" — consider adding to terminology.md", + "warning", + )) + return issues + + +# Cache glossary terms once at module level +_glossary_cache: Optional[set] = None + +def _get_glossary() -> set: + global _glossary_cache + if _glossary_cache is None: + _glossary_cache = load_glossary_terms() + return _glossary_cache + + +def run_all_checks(filepath: Path) -> List[Issue]: + """Run all checks on a single file.""" + content = filepath.read_text(encoding="utf-8") + lines = content.split("\n") + + issues = [] + issues.extend(check_frontmatter(content, str(filepath))) + issues.extend(check_settings_paths(lines, str(filepath))) + issues.extend(check_ui_element_backticks(lines, str(filepath))) + issues.extend(check_header_case(lines, str(filepath))) + issues.extend(check_image_alt_text(lines, str(filepath))) + issues.extend(check_callout_syntax(lines, str(filepath))) + issues.extend(check_product_casing(lines, str(filepath))) + issues.extend(check_oz_terms(lines, str(filepath))) + issues.extend(check_deprecated_terms(lines, str(filepath))) + issues.extend(check_unrecognized_terms(lines, str(filepath), _get_glossary())) + return issues + + +# --------------------------------------------------------------------------- +# Fix +# --------------------------------------------------------------------------- + +def apply_fixes(filepath: Path, issues: List[Issue]) -> int: + """Apply fixable issues to a file. Returns count of fixes applied.""" + fixable = [i for i in issues if i.fixable and i.fix_from and i.fix_to] + if not fixable: + return 0 + + content = filepath.read_text(encoding="utf-8") + count = 0 + for issue in fixable: + if issue.fix_from in content: + content = content.replace(issue.fix_from, issue.fix_to, 1) + count += 1 + + if count > 0: + filepath.write_text(content, encoding="utf-8") + return count + + +# --------------------------------------------------------------------------- +# Reporting +# --------------------------------------------------------------------------- + +def print_report(report: Report) -> None: + """Print human-readable report to stdout.""" + print(f"\n=== STYLE LINT REPORT ===") + print(f"Files scanned: {report.files_scanned}") + print(f"Issues found: {len(report.issues)}") + if report.fixes_applied > 0: + print(f"Fixes applied: {report.fixes_applied}") + + if not report.issues: + print("\n✅ No issues found.") + return + + # Group by check type + by_check: dict = {} + for issue in report.issues: + by_check.setdefault(issue.check, []).append(issue) + + for check, issues in sorted(by_check.items()): + print(f"\n### {check.upper()} ({len(issues)} found)") + for issue in issues[:20]: # Cap display at 20 per category + marker = "⚠️" if issue.severity == "warning" else "❌" + print(f" {marker} {issue.file}:{issue.line}") + print(f" {issue.message}") + if len(issues) > 20: + print(f" ... and {len(issues) - 20} more") + + +def save_json(report: Report, output_path: str) -> None: + """Save report as JSON.""" + data = { + "files_scanned": report.files_scanned, + "total_issues": len(report.issues), + "fixes_applied": report.fixes_applied, + "issues": [ + { + "file": i.file, "line": i.line, "check": i.check, + "message": i.message, "severity": i.severity, "fixable": i.fixable, + } + for i in report.issues + ], + } + with open(output_path, "w") as f: + json.dump(data, f, indent=2) + print(f"\nResults saved to {output_path}") + + +def send_slack(report: Report, channel: str) -> None: + """Send report summary to Slack.""" + token = os.environ.get("SLACK_BOT_TOKEN") + if not token: + print("Warning: SLACK_BOT_TOKEN not set, skipping Slack notification.") + return + if not report.issues: + return # Don't notify on clean runs + + try: + import requests + except ImportError: + print("Warning: 'requests' not installed, skipping Slack notification.") + return + + by_check: dict = {} + for issue in report.issues: + by_check.setdefault(issue.check, []).append(issue) + + lines = [f"*Style Lint Report* — {len(report.issues)} issues in {report.files_scanned} files"] + for check, issues in sorted(by_check.items()): + lines.append(f"• *{check}*: {len(issues)}") + + text = "\n".join(lines) + resp = requests.post( + "https://slack.com/api/chat.postMessage", + headers={"Authorization": f"Bearer {token}"}, + json={"channel": channel, "text": text}, + ) + if resp.ok and resp.json().get("ok"): + print(f"Slack notification sent to {channel}") + else: + print(f"Warning: Slack notification failed: {resp.text}") + + +def create_pr_with_fixes() -> None: + """Create a branch and PR with the auto-fixes.""" + branch = "fix/style-lint-auto-fixes" + subprocess.run(["git", "checkout", "-b", branch], check=True) + subprocess.run(["git", "add", "docs/"], check=True) + result = subprocess.run(["git", "diff", "--cached", "--quiet"]) + if result.returncode == 0: + print("No changes to commit.") + return + subprocess.run([ + "git", "commit", "-m", + "docs: auto-fix style lint issues\n\nCo-Authored-By: Oz <oz-agent@warp.dev>", + ], check=True) + subprocess.run(["git", "push", "origin", branch], check=True) + subprocess.run([ + "gh", "pr", "create", + "--title", "docs: auto-fix style lint issues", + "--body", "Automated fixes from `style_lint.py --fix`.\n\nCo-Authored-By: Oz <oz-agent@warp.dev>", + ], check=True) + + +# --------------------------------------------------------------------------- +# Main +# --------------------------------------------------------------------------- + +def main() -> None: + parser = argparse.ArgumentParser(description="Style lint for Warp Astro Starlight docs") + mode = parser.add_mutually_exclusive_group() + mode.add_argument("--all", action="store_true", default=True, help="Scan all docs (default)") + mode.add_argument("--changed", action="store_true", help="Scan only changed files") + parser.add_argument("--fix", action="store_true", help="Auto-fix high-confidence issues") + parser.add_argument("--create-pr", action="store_true", help="Create PR with fixes") + parser.add_argument("--output", type=str, help="Save JSON report to file") + parser.add_argument("--slack-notify", action="store_true", help="Send results to Slack") + parser.add_argument("--slack-channel", type=str, default=DEFAULT_SLACK_CHANNEL) + args = parser.parse_args() + + if args.create_pr: + args.fix = True + + # Discover files + files = find_changed_md_files() if args.changed else find_all_md_files() + report = Report(files_scanned=len(files)) + + # Run checks + for filepath in files: + issues = run_all_checks(filepath) + if args.fix: + fixed = apply_fixes(filepath, issues) + report.fixes_applied += fixed + # Re-check after fixes to get remaining issues + issues = run_all_checks(filepath) + report.issues.extend(issues) + + # Output + print_report(report) + if args.output: + save_json(report, args.output) + if args.slack_notify: + send_slack(report, args.slack_channel) + if args.create_pr and report.fixes_applied > 0: + create_pr_with_fixes() + + # Exit code: 1 if errors found, 0 otherwise + errors = [i for i in report.issues if i.severity == "error"] + sys.exit(1 if errors else 0) + + +if __name__ == "__main__": + main() diff --git a/.warp/skills/sync-error-docs/SKILL.md b/.warp/skills/sync-error-docs/SKILL.md new file mode 100644 index 0000000..63927d8 --- /dev/null +++ b/.warp/skills/sync-error-docs/SKILL.md @@ -0,0 +1,138 @@ +--- +name: sync-error-docs +description: >- + Detect new platform error codes in warp-server that are missing documentation + pages in the docs repo. Creates doc pages, astro.config.mjs (sidebar config) entries, and + redirects for any gaps. Use on a weekly schedule or when error codes change. +--- + +# Sync Error Docs + +Ensure every `ErrorCode` in `platformerrors.go` has a corresponding documentation page, astro.config.mjs (sidebar config) entry, and redirects. + +## Repos + +This skill requires two repos in the agent's environment: + +- `warpdotdev/warp-server` — source of truth for error codes +- `warpdotdev/docs` — documentation pages + +## Workflow + +### Step 1: Extract error codes from warp-server + +Grep the `ErrorCode` constants from `platformerrors.go`: + +```bash +grep 'ErrorCode = "' warp-server/logic/ai/ambient_agents/platformerrors/platformerrors.go +``` + +Each match yields a line like `InsufficientCredits ErrorCode = "insufficient_credits"`. Extract the quoted string — that is the canonical error code (underscore format). + +### Step 2: List existing doc pages + +List the markdown files in the errors directory: + +```bash +ls docs/src/content/docs/reference/api-and-sdk/troubleshooting/errors/*.mdx +``` + +Each file is named `{hyphen-code}.mdx` (e.g., `insufficient-credits.mdx`). Ignore `index.mdx`. + +### Step 3: Compare and find missing pages + +For each error code from Step 1, convert underscores to hyphens (e.g., `insufficient_credits` → `insufficient-credits`) and check whether a corresponding `.mdx` file exists. + +### Step 4: Create missing doc pages + +For each missing code, read `references/error-page-template.md` in this skill directory for the template. + +**Heading case:** All headings (H1–H4) must use sentence case — capitalize only the first word and proper feature names. ✅ `## When does this occur?` ❌ `## When Does This Occur?` + +To fill in the template accurately: +1. Read the error code's doc comment and `FromError()` case in `platformerrors.go` to determine: + - HTTP status code + - Whether it's retryable + - Whether it's a user error (FAILED) or platform error (ERROR) + - The user-facing message +2. If the code has a dedicated constructor (e.g., `NewExternalAuthRequired`), read it for additional context + +Place the new file at: +``` +docs/src/content/docs/reference/api-and-sdk/troubleshooting/errors/{hyphen-code}.mdx +``` + +### Step 5: Add to astro.config.mjs (sidebar config) + +Add the new page to `docs/src/content/docs/reference/astro.config.mjs (sidebar config)` under the Errors section. + +- User errors: insert before `authentication_required` (which begins the platform errors group) +- Platform errors: append after `internal_error` (currently the last entry in the list) +- Note: the list has no explicit section labels. The platform errors group starts at `authentication_required` and currently contains `authentication_required`, `resource_unavailable`, and `internal_error`. +- Use the format: ` * [{underscore\_code}](api-and-sdk/troubleshooting/errors/{hyphen-code}.md)` +- Note: underscores in the display name must be escaped as `\_` for Astro Starlight + +### Step 6: Add vercel.json (redirects) redirect + +Add a redirect entry in `docs/src/content/docs/reference/vercel.json (redirects)` that maps the underscore path to the hyphen path. This handles visitors who type the underscore form directly: + +```yaml +api-and-sdk/troubleshooting/errors/{underscore_code}: api-and-sdk/troubleshooting/errors/{hyphen-code}.md +``` + +Before adding, check if the entry already exists to avoid duplicates on re-runs: + +```bash +grep 'api-and-sdk/troubleshooting/errors/{underscore_code}:' docs/src/content/docs/reference/vercel.json (redirects) +``` + +If it returns a match, skip this step. Otherwise, add the entry under the existing `redirects:` block. + +### Step 7: Create site-level redirect + +The API's `type` URI uses the format `https://docs.warp.dev/errors/{underscore_code}`. This needs a site-level redirect to reach the actual doc page. + +<!-- TODO: Post-migration, update this step to use vercel.json redirects instead of the GitBook API. --> +Use the existing `docs_redirects.py` script (requires `GITBOOK_TOKEN` env var and `requests` Python package). + +First, check if the redirect already exists to avoid duplicates on re-runs: + +```bash +python3 docs/scripts/docs_redirects.py get-by-source \ + --source "/errors/{underscore_code}" +``` + +If a redirect is returned, skip the `create` step. Otherwise, create it: + +```bash +python3 docs/scripts/docs_redirects.py create \ + --source "/errors/{underscore_code}" \ + --destination-json '{"kind": "url", "url": "https://docs.warp.dev/reference/api-and-sdk/troubleshooting/errors/{hyphen-code}"}' +``` + +Read `references/redirect-patterns.md` in this skill directory for more details on the redirect setup. + +If `GITBOOK_TOKEN` is not set, skip this step and note it in the report. + +### Step 8: Commit and open PR + +If any pages were created: + +1. Create a branch in the docs repo (e.g., `sync-error-docs/{date}`) +2. Commit all changes with a descriptive message +3. Push and open a PR targeting `main` +4. Use `report_pr` to surface the PR link + +### Step 9: Report + +Summarize what was found: +- Total error codes in `platformerrors.go` +- Number of existing doc pages +- New codes that were missing pages (list them) +- Pages created, astro.config.mjs (sidebar config) entries added, redirects configured +- Or confirm everything is already in sync + +## References + +- `references/error-page-template.md` — template for new error doc pages +- `references/redirect-patterns.md` — detailed redirect setup instructions diff --git a/.warp/skills/sync-error-docs/references/error-page-template.md b/.warp/skills/sync-error-docs/references/error-page-template.md new file mode 100644 index 0000000..a9210d6 --- /dev/null +++ b/.warp/skills/sync-error-docs/references/error-page-template.md @@ -0,0 +1,87 @@ +# Error Page Template + +Use this template when creating a new error documentation page. Replace all `{PLACEHOLDER}` values. + +## Template + +```markdown +--- +description: >- + {SHORT_DESCRIPTION_TWO_LINES} +--- + +# {underscore\_code} + +The `{underscore_code}` error occurs when {PLAIN_ENGLISH_EXPLANATION}. + +*** + +## Details + +* **HTTP Status:** `{STATUS_CODE} {STATUS_TEXT}` +* **Retryable:** {Yes/No} +* **Task State:** {FAILED/ERROR} + +*** + +## When does this occur? + +This error is returned when: + +* {CONDITION_1} +* {CONDITION_2} +* {CONDITION_3} + +*** + +## Example response + +\```json +{ + "type": "https://docs.warp.dev/reference/api-and-sdk/troubleshooting/errors/{hyphen-code}", + "title": "{USER_FACING_MESSAGE}", + "status": {STATUS_CODE_INT}, + "instance": "/api/v1/agent/tasks", + "error": "{USER_FACING_MESSAGE}", + "retryable": {true/false}, + "trace_id": "abc123..." +} +\``` + +*** + +## How to resolve + +1. {RESOLUTION_STEP_1} +2. {RESOLUTION_STEP_2} +3. {RESOLUTION_STEP_3} + +*** + +## Related + +* [Oz Agent API & SDK](https://docs.warp.dev/reference/api-and-sdk/agent) — API reference +* [Cloud Agents Overview](https://docs.warp.dev/agent-platform/cloud-agents/overview) — How cloud agents work +``` + +## Placeholder reference + +- `{underscore_code}` — The error code as defined in `platformerrors.go` (e.g., `insufficient_credits`) +- `{underscore\_code}` — Same but with underscores escaped for Astro Starlight H1 headings (e.g., `insufficient\_credits`) +- `{hyphen-code}` — The code with hyphens for URLs/filenames (e.g., `insufficient-credits`) +- `{SHORT_DESCRIPTION_TWO_LINES}` — A 1–2 line description for the YAML frontmatter `description` field +- `{STATUS_CODE}` / `{STATUS_TEXT}` — HTTP status (e.g., `403 Forbidden`). Get from `FromError()` or the constructor in `platformerrors.go` +- `{FAILED/ERROR}` — `FAILED` for user errors (`IsUserError() == true`), `ERROR` for platform errors +- `{USER_FACING_MESSAGE}` — The message from `FromError()` or the constructor's `userFacingMessage` field +- `{true/false}` for retryable — From the `Retryable()` method or `retryable` field +- `"trace_id"` — Include this field only when the resolution steps direct users to contact Warp support (support needs it to investigate). Omit entirely for self-serve resolutions. + +## Conventions + +- The H1 title uses the underscore form with `\_` escaping (Astro Starlight renders underscores as italics otherwise) +- The opening paragraph uses backtick-wrapped underscore form: `` `insufficient_credits` `` +- The example JSON `type` field uses the full doc page URL (not the short `/errors/` redirect) +- Include `trace_id` in the example JSON only when the resolution steps direct users to contact Warp support — support needs it to investigate. Omit entirely for self-serve resolutions (e.g. buy credits, update API key, wait and retry). +- Platform errors should include a `:::note` callout explaining the ERROR vs FAILED distinction (see `authentication-required.md` for an example) +- Keep resolution steps actionable and numbered +- Related links should be relevant to the specific error (billing page for credit errors, environment page for setup errors, etc.) diff --git a/.warp/skills/sync-error-docs/references/redirect-patterns.md b/.warp/skills/sync-error-docs/references/redirect-patterns.md new file mode 100644 index 0000000..0e53da6 --- /dev/null +++ b/.warp/skills/sync-error-docs/references/redirect-patterns.md @@ -0,0 +1,84 @@ +# Redirect Patterns + +Two types of redirects are needed for each error code to ensure the API's `type` URI resolves to the correct documentation page. + +## Background + +The `platformerrors` package defines `ProblemTypeBaseURI = "https://docs.warp.dev/errors/"`. API error responses include a `type` field like: + +``` +https://docs.warp.dev/errors/insufficient_credits +``` + +But the actual documentation page lives at: + +``` +https://docs.warp.dev/reference/api-and-sdk/troubleshooting/errors/insufficient-credits +``` + +Two redirects bridge this gap: +1. A **site-level redirect** from `/errors/{underscore_code}` to the full doc page URL +2. A **Astro Starlight space redirect** from the underscore filename to the hyphen filename (within the reference space) + +## 1. Site-level redirect (Astro Starlight API) + +<!-- TODO: Post-migration, update this to use vercel.json redirects instead of the GitBook API. --> +This redirect is created via the GitBook API using `scripts/docs_redirects.py`. It requires the `GITBOOK_TOKEN` environment variable. + +### Create a redirect + +```bash +python3 docs/scripts/docs_redirects.py create \ + --source "/errors/{underscore_code}" \ + --destination-json '{"kind": "url", "url": "https://docs.warp.dev/reference/api-and-sdk/troubleshooting/errors/{hyphen-code}"}' +``` + +### Check if a redirect already exists + +```bash +python3 docs/scripts/docs_redirects.py get-by-source \ + --source "/errors/{underscore_code}" +``` + +### List existing error redirects + +```bash +python3 docs/scripts/docs_redirects.py list --search "/errors/" +``` + +### Notes + +- The script uses hardcoded org ID (`-MbqIZLCtzerswjFm7mh`) and site ID (`site_FKhQ8`) which are the Warp docs defaults +- If `GITBOOK_TOKEN` is not set, skip this step and report it — the redirect can be created manually later +- The destination `kind` is `"url"` (external URL redirect), not `"site-page"` + +## 2. Astro Starlight space redirect (vercel.json (redirects)) + +This redirect lives in `docs/src/content/docs/reference/vercel.json (redirects)` and handles in-space navigation where someone might visit the underscore form of the path. + +### Format + +Add an entry under the `redirects:` key: + +```yaml +redirects: + # ... existing redirects ... + + # Error code underscore→hyphen redirects + api-and-sdk/troubleshooting/errors/{underscore_code}: api-and-sdk/troubleshooting/errors/{hyphen-code}.md +``` + +### Example + +For `insufficient_credits`: + +```yaml + api-and-sdk/troubleshooting/errors/insufficient_credits: api-and-sdk/troubleshooting/errors/insufficient-credits.md +``` + +### Notes + +- Paths are relative to the space root (defined by `root: ./` in the yaml) +- The source path has NO leading slash and NO `.md` extension +- The destination path includes the `.md` extension +- Group error redirect entries together with a comment for clarity diff --git a/.warp/skills/sync_terminology/SKILL.md b/.warp/skills/sync_terminology/SKILL.md new file mode 100644 index 0000000..22a70e0 --- /dev/null +++ b/.warp/skills/sync_terminology/SKILL.md @@ -0,0 +1,178 @@ +--- +name: sync_terminology +description: >- + Sync the Warp terminology glossary from the Notion Dictionary to the repo. + Fetches the Notion Dictionary page, compares with .warp/references/terminology.md, + and opens a PR for any additions or changes. Flags repo-only terms that are + missing from Notion. Use on a weekly schedule or manually when terminology changes. +--- + +# Sync Terminology from Notion + +Keep `.warp/references/terminology.md` in sync with the canonical Notion Dictionary. + +**Direction:** Notion → repo. Notion is the source of truth. If the repo has terms not in Notion, flag them for addition to Notion rather than removing them from the repo. + +## Prerequisites + +- Notion MCP server must be connected and authenticated +- `gh` CLI must be available and authenticated +- You must be in the `warpdotdev/docs` repo + +## Workflow + +### Step 1: Fetch the Notion Dictionary + +Use the Notion MCP to fetch the Dictionary page: + +``` +notion-fetch with id: "NOTION_DICTIONARY_PAGE_ID" +``` + +The page has two sections: +- **Rules section** — Uses "Use / Avoid / Notes" format for capitalization and naming consistency +- **Terminology section** — Uses glossary format with definitions and usage notes + +Parse both sections. Extract each term with its: +- **Name** (the canonical form) +- **Definition or rule** (the "Use" form, or the glossary definition) +- **Avoid forms** (if any) +- **Notes** (if any) +- **Category** (infer from the Notion page's heading structure) + +### Step 2: Read the current terminology.md + +Read `.warp/references/terminology.md` from the repo. Parse each entry, extracting: +- **Name** (the bolded term) +- **Definition** (the text after the em dash) +- **Usage note** (the italic `*Usage note:*` line, if present) +- **Category** (the `##` heading the term falls under) + +### Step 3: Compare in both directions + +#### Notion → repo (new or changed terms) +For each term in Notion, check if it exists in `terminology.md`: +- **New term:** exists in Notion but not in the repo file +- **Changed term:** exists in both, but the definition, avoid forms, or notes differ meaningfully (ignore minor formatting differences) + +#### Repo → Notion (orphaned terms) +For each term in `terminology.md`, check if it exists in the Notion Dictionary: +- **Orphaned term:** exists in the repo but not in Notion + +Collect both lists. + +### Step 4: If no differences, exit + +If both lists are empty, report "Terminology is in sync" and stop. Do not create a branch or PR. + +### Step 5: Update terminology.md with Notion changes + +If there are new or changed terms from Notion: + +1. Create a new branch: + ```bash + git checkout -b sync-terminology/YYYY-MM-DD + ``` + +2. For each **new term**, add it to the appropriate category section in `terminology.md`: + - Match the category from Notion to the existing `##` sections in the file + - If no matching section exists, create a new `##` section + - Insert alphabetically within the section + - Use the standard format: + ```markdown + - **Term** — Definition. + *Usage note:* Additional guidance. + ``` + - For "Avoid" rules from Notion's Rules section, format as: + ```markdown + - ❌ **Avoided Term** — Explanation. Use "Preferred Form" instead. + ``` + +3. For each **changed term**, update the existing entry to match Notion. + +4. Also update the corresponding summary entries in `AGENTS.md` under `## Terminology standards` if the term appears there. The AGENTS.md section is a summary — only add terms there if they are core features, Oz terms, technical terms, billing terms, or UI elements. + +### Step 6: Commit and open a PR + +```bash +git add .warp/references/terminology.md AGENTS.md +git commit -m "docs: sync terminology from Notion Dictionary + +Co-Authored-By: Oz <oz-agent@warp.dev>" +git push origin sync-terminology/YYYY-MM-DD +``` + +Open a PR: +- **Title:** `docs: sync terminology from Notion Dictionary` +- **Body:** Include: + - List of terms added (with definitions) + - List of terms changed (with before/after) + - List of orphaned terms in the repo that are missing from Notion (see Step 7) +- **Labels:** `documentation` + +Use `report_pr` to surface the PR link. + +### Step 7: Flag orphaned repo terms + +If there are terms in the repo that are not in Notion, include a section in the PR body: + +```markdown +## Terms in repo but missing from Notion + +The following terms exist in `terminology.md` but were not found in the +Notion Dictionary. Please add these to the Dictionary page, or let us +know if they should be removed from the repo. + +- **Term 1** — definition +- **Term 2** — definition +``` + +This ensures the repo doesn't silently accumulate terms that bypass Notion. + +## Mapping Notion format to terminology.md format + +### Rules section entries (Use / Avoid / Notes) + +Notion format: +``` +- Agent Mode vs agent mode + - Use: Agent Mode + - Avoid: agent mode, Agent mode + - Notes: Treat as a feature name. +``` + +Becomes in terminology.md: +```markdown +- **Agent Mode** — The mode where Warp interprets your input as a request to an Agent (not a shell command). + *Usage note:* Not "agent mode" or "Agent-mode." +``` + +Keep any existing definition from terminology.md. Only update the usage note / avoid guidance from Notion. + +### Terminology section entries (glossary format) + +These map directly — both use term + definition + usage note format. Align the wording with Notion. + +## Category mapping + +Map Notion headings to terminology.md `##` sections: + +- "Capitalization and naming" → distribute terms to their matching category (Core product terms, Navigation and UI terms, etc.) +- "UI surface names" → Navigation and UI terms +- "Untraditional or branded terms" → Branded and informal terms +- "Hyphenation and phrasing" → Technical terms +- Direct category matches (e.g., "Oz terminology" → Oz terminology) + +If a term doesn't clearly fit an existing category, place it in the most logical section and note the placement in the PR body. + +## Schedule + +Run weekly (Monday morning) or manually when terminology changes are expected. + +## Troubleshooting + +### Notion MCP auth failure +If the Notion MCP returns an auth error, report the failure and exit without making changes. Do not fall back to a cached version. + +### Merge conflicts +If the branch has merge conflicts with `main`, rebase and resolve. Terminology entries are independent lines, so conflicts are rare. diff --git a/.warp/skills/update-changelog/SKILL.md b/.warp/skills/update-changelog/SKILL.md new file mode 100644 index 0000000..096284c --- /dev/null +++ b/.warp/skills/update-changelog/SKILL.md @@ -0,0 +1,235 @@ +--- +name: update-changelog +description: Update the public changelog at docs.warp.dev/changelog with the latest stable release. Fetches changelog data from channel-versions, formats a new entry, and opens a PR. Use after a stable release ships (typically Fridays). +--- + +# Update Changelog + +Adds a new entry to `src/content/docs/changelog/index.mdx` for the latest stable Warp release, then opens a PR. + +## Related Skills + +- `create_pr` - PR creation guidelines for this repo + +## Workflow + +### Step 1: Get the latest stable version + +Fetch the current stable version from the public channel versions endpoint: + +```bash +curl -s "https://releases.warp.dev/channel_versions.json" | python3 -c " +import sys, json +d = json.load(sys.stdin) +print(d['stable']['version']) +" +``` + +This returns the full version string, e.g. `v0.2026.02.18.08.22.stable_02`. + +Parse it into components: +- **Full version**: `v0.2026.02.18.08.22.stable_02` (used to look up the changelog entry in channel-versions) +- **Base version**: `v0.2026.02.18.08.22` (strip everything after the last `.` that starts with a channel name: `stable`, `preview`, `dev`, `canary`, `beta`). The base version is the version without the `{channel}_{patch}` suffix. +- **Display date**: `2026.02.18` (extract `YYYY.MM.DD` from the base version, stripping the leading `v0.`) +- **Display version**: Same as base version (e.g. `v0.2026.02.18.08.22`) + +### Step 2: Check if already documented + +Read `src/content/docs/changelog/index.mdx` and search for the base version in existing `### ` header lines. If found, report that the changelog is already up to date and stop. + +### Step 3: Fetch changelog data from `channel_versions.json` (primary source) + +The authoritative source for changelog content is the `channel_versions.json` file in the `warpdotdev/channel-versions` repo. This file contains the final, human-reviewed changelog with all sections — New features, Improvements, Bug fixes, and oz_updates. + +**IMPORTANT**: The docs changelog entry MUST match the content in `channel_versions.json` exactly — 1:1, no additions, removals, or rewording. Use `markdown_sections` values directly. + +Fetch the stable changelog entry for the current version: + +```bash +gh api repos/warpdotdev/channel-versions/contents/channel_versions.json \ + --jq '.content' | base64 -d | python3 -c " +import sys, json +d = json.load(sys.stdin) +entry = d['changelogs']['stable'].get('{full_version}') +if entry: + print(json.dumps(entry, indent=2)) +else: + print('NOT_FOUND') +" +``` + +The entry has this structure: + +```json +{ + "date": "2026-02-26T08:22:00+0000", + "markdown_sections": [ + {"title": "New features", "markdown": "* item 1\n* item 2"}, + {"title": "Improvements", "markdown": "* item 1\n* item 2"}, + {"title": "Bug fixes", "markdown": "* item 1\n* item 2"} + ], + "sections": [], + "oz_updates": ["markdown string 1"] +} +``` + +Key fields: +- `markdown_sections` — pre-formatted bullet lists for ALL sections: New features, Improvements, AND Bug fixes. Use these directly. +- `oz_updates` — optional. Oz-specific update entries. If present and non-empty, include as a separate **Oz updates** section (not merged into Improvements). +- `image_url` — optional. If present, include a `<figure>` element. + +**Processing the markdown values**: The `markdown` values may have leading whitespace on lines after the first (e.g. ` * item`). Strip leading whitespace from each line so they become `* item`. + +Ignore any `"Coming soon"` section — it's always empty and not used in the public changelog. + +### Step 4: Fallback — fetch from GCS and warp-internal PRs + +**Only use this step if Step 3 returns `NOT_FOUND`** (e.g. the channel-versions release PR hasn't merged yet). + +If falling back, note in the PR description that the entry was generated from fallback sources and should be cross-checked against channel-versions once the release PR merges. + +#### 4a. Fetch from GCS + +Download the structured changelog from GCS: + +```bash +curl -s "https://releases.warp.dev/stable/{full_version}/changelog.json" +``` + +This file may contain only New features and Improvements (no bug fixes). Use `markdown_sections` and `oz_updates` from it. + +#### 4b. Fetch bug fixes from warp-internal PRs + +Since the GCS file omits bug fixes, query merged PRs in warp-internal between the current and previous stable release tags. + +**Find the previous stable release tag:** + +```bash +gh release list --repo warpdotdev/warp-internal --limit 20 --json tagName --jq '.[].tagName' | grep '\.stable_' +``` + +Group by base version and take the two most recent distinct base versions. The **current** tag matches the version from Step 1; the **previous** tag is the next-oldest base version. + +**Find PRs merged between the two tags:** + +```bash +gh api "repos/warpdotdev/warp-internal/compare/{previous_tag}...{current_tag}" \ + --paginate --jq '.commits[].commit.message' | grep -oP '\(#\K\d+' | sort -un +``` + +**Extract CHANGELOG-BUG-FIX entries from PR bodies:** + +```bash +gh pr view {pr_number} --repo warpdotdev/warp-internal --json body --jq '.body' | \ + grep -i '^CHANGELOG-BUG-FIX:' | sed -E 's/^[Cc][Hh][Aa][Nn][Gg][Ee][Ll][Oo][Gg]-[Bb][Uu][Gg]-[Ff][Ii][Xx]:[[:space:]]*//' +``` + +Collect all extracted bug fix entries. Also extract any `CHANGELOG-OZ:` entries the same way if not already covered by `oz_updates` in the JSON. + +Strip the `{{text goes here...}}` placeholder template text — only include entries where the author filled in actual content. Deduplicate identical entries. + +#### 4c. Review entries for sensitive content + +Before including bug fix entries in the public changelog (docs.warp.dev/changelog), review each one for potentially sensitive information. **Do NOT include entries that reference**: +- Security vulnerabilities or exploits (e.g. "Fixed authentication bypass", "Fixed XSS in...") +- Internal infrastructure or architecture details not already public +- Customer-specific issues or data + +For security-related fixes, either omit entirely or use a generic description (e.g. "Fixed a security issue" or "Stability and security improvements"). + +If you're unsure whether an entry is safe to publish, flag it in the PR description for human review. + +### Step 5: Format the changelog entry + +Build the entry matching the exact format used in `src/content/docs/changelog/index.mdx`. **Read the 2-3 most recent entries in the file** to confirm the current format before writing. + +The standard format is: + +```markdown +### {display_date} ({display_version}) + +**New features** + +* Entry from markdown_sections +* Another entry + +**Improvements** + +* Entry from markdown_sections + +**Bug fixes** + +* Entry from markdown_sections + +**Oz updates** + +* Entry from oz_updates +``` + +Formatting rules: + +1. **Header**: `### YYYY.MM.DD (vX.YYYY.MM.DD.HH.MM)` — use display_date and display_version from Step 1 +2. **Section order**: New features → Improvements → Bug fixes → Oz updates +3. **Only include sections that have entries** — skip any section with no content +4. **Blank lines**: One blank line after the header, one blank line after each `**section title**`, one blank line between sections +5. **Bullet format**: Each entry is `* Entry text` (single asterisk, space, text) +6. **Image handling**: If `image_url` is present in changelog.json, insert a `<figure>` element on its own line after the `**New features**` header and blank line, before the bullet points: + +```markdown +**New features** + +<figure><img src="{image_url}" alt="description of the image"><figcaption></figcaption></figure> + +* First bullet point +``` + +Reference the `2026.02.10` entry in the existing changelog for the exact `<figure>` format. Use a brief, descriptive alt text. + +7. **Markdown from GCS**: The `markdown_sections[].markdown` values are already formatted as `* text\n* text` — use them directly. Split on newlines and include each line as-is. +8. **No trailing whitespace** on any lines. + +### Step 6: Insert into the changelog file + +Edit `src/content/docs/changelog/index.mdx`: +- Find the first line that starts with `### ` (this is the most recent existing entry) +- Insert the new entry **immediately before** that line +- Ensure there is exactly one blank line between the description paragraph ("Submit bugs and feature requests...") and the new entry's `### ` header +- Ensure there is exactly one blank line between the end of the new entry and the next `### ` header + +### Step 7: Create branch, commit, and open PR + +```bash +# Create a new branch +git checkout -b changelog/{base_version} + +# Stage and commit +git add src/content/docs/changelog/index.mdx +git commit -m "docs: add changelog entry for {base_version} + +Co-Authored-By: Oz <oz-agent@warp.dev>" + +# Push and create PR +git push origin changelog/{base_version} +gh pr create \ + --title "docs: changelog {base_version}" \ + --body "Adds changelog entry for the {base_version} stable release. + +Co-Authored-By: Oz <oz-agent@warp.dev>" +``` + +## Manual / Backfill Mode + +If you need to add entries for a specific version (not necessarily the latest), the user will provide the full version string. Use that instead of fetching from `channel_versions.json` in Step 1, then proceed with Steps 2-7 as normal. + +If `gh` access to channel-versions is unavailable, fall back to Step 4 (GCS + warp-internal PRs) and note in the PR description that the entry should be cross-checked against channel-versions. + +## Example + +For version `v0.2026.02.18.08.22.stable_02`: + +1. Base version: `v0.2026.02.18.08.22` +2. Display date: `2026.02.18` +3. Display version: `v0.2026.02.18.08.22` +4. channel-versions key: `changelogs.stable["v0.2026.02.18.08.22.stable_02"]` +5. Header: `### 2026.02.18 (v0.2026.02.18.08.22)` +6. Branch: `changelog/v0.2026.02.18.08.22` diff --git a/.warp/skills/validate_ui_refs/SKILL.md b/.warp/skills/validate_ui_refs/SKILL.md new file mode 100644 index 0000000..8b76f2b --- /dev/null +++ b/.warp/skills/validate_ui_refs/SKILL.md @@ -0,0 +1,181 @@ +--- +name: validate_ui_refs +description: Scan Warp Astro Starlight documentation for UI menu paths and Command Palette command names, then validate them against the warp-internal codebase for accuracy. Catch and surface outdated steps automatically. +--- + +# Validate UI References + +This skill scans Warp's Astro Starlight documentation for references to UI paths (e.g. `Settings > AI > Active AI`) and Command Palette command names (e.g. "Open Theme Picker"), then validates them against a snapshot of known-valid paths extracted from the `warp-internal` codebase. + +## Running the Check + +From the docs repo root: + +```bash +python3 .warp/skills/validate_ui_refs/validate_ui_refs.py --all +``` + +### Options + +- `--check-paths`: Only validate UI menu paths (Settings, File, View, Warp Drive) +- `--check-commands`: Only validate Command Palette names +- `--check-format`: Check that UI paths use the canonical bold format: **Settings** > **AI** > **Active AI** +- `--all`: Run all checks (default) +- `--fix`: Auto-fix high-confidence issues (e.g. case mismatches) +- `--create-pr`: Create a branch and PR with auto-fixes (requires `gh` CLI) +- `--slack-notify`: Post results to Slack (only sends when issues are found; requires `SLACK_BOT_TOKEN` and `SLACK_CHANNEL_ID` env vars) +- `--slack-channel ID`: Override default Slack channel +- `--include-changelog`: Include `changelog/` in the scan (excluded by default since it's a historical record) +- `--refresh-valid-paths`: Re-extract valid paths from `warp-internal` and update `valid_paths.json` +- `--warp-internal-path PATH`: Path to the `warp-internal` repo (default: `../warp-internal` relative to docs root, or `WARP_INTERNAL_PATH` env var) +- `--output FILE`: Save results to a JSON file + +### Quick path-only check: + +```bash +python3 .warp/skills/validate_ui_refs/validate_ui_refs.py --check-paths +``` + +### Full check with auto-fix and PR: + +```bash +python3 .warp/skills/validate_ui_refs/validate_ui_refs.py --all --fix --create-pr +``` + +## Output Format + +The script outputs a report like: + +``` +=== UI REFERENCE VALIDATION REPORT === +Generated: 2026-02-19T00:17:00Z +Files scanned: 174 + +### SETTINGS PATH ISSUES (5 found) +❌ "Current Theme" is not a known sub-section of Appearance + themes.md:26 + Path: Settings > Appearance > Current Theme + Suggestion: Valid sub-sections: Themes, Icon, Window, Input, Panes, Blocks, Text, Cursor, Tabs, Full-screen Apps + +⚠️ "active ai" is not a known sub-section of AI + codebase-context.md:34 + Path: Settings > AI > active ai + Suggestion: Did you mean "Active AI"? (score: 0.92) + +### COMMAND PALETTE ISSUES (1 found) +❌ UNMATCHED COMMAND + themes.md:26 + Reference: "Open Theme Creator" + Did you mean "Open theme picker"? (score: 0.85) +``` + +## Refreshing Valid Paths + +The `valid_paths.json` file is a static snapshot of valid UI paths. To update it from the latest `warp-internal` source: + +```bash +python3 .warp/skills/validate_ui_refs/validate_ui_refs.py --refresh-valid-paths --warp-internal-path /path/to/warp-internal +``` + +This parses: +- `SettingsSection` enum and `Display` impl from `settings_view/mod.rs` +- `Category::new(...)` and `build_sub_header(...)` calls from settings page files +- `EditableBinding::new(...)` registrations from `terminal/view/init.rs` and `workspace/mod.rs` + +The macOS menu bar and Warp Drive sections are maintained as manual lists in `valid_paths.json` since they change infrequently. + +## What Gets Validated + +### UI Paths +- **Settings paths**: `Settings > [Section] > [Sub-section]` — validates section and sub-section names against the `SettingsSection` enum +- **macOS menu bar**: `File > ...`, `View > ...`, `Warp > ...` — validates against known menu items +- **Warp Drive**: `Warp Drive > ...`, `Personal > ...` — validates against known spaces and object types +- **Multiple markdown formats**: backtick-wrapped, bold, italic, and bare inline paths + +### Format Consistency +- All UI paths should use per-segment bold formatting: **Settings** > **AI** > **Active AI** +- Backtick formatting (`` `Settings > AI` ``), full bold wrapping (`**Settings > AI**`), italic, and bare formats are flagged +- Auto-fix with `--fix` converts non-canonical paths to the correct bold format + +### UI Element Formatting +- Clickable UI elements (buttons, toggles, links, dropdowns) should be bold, not backtick: Click **Save**, not Click `Save` +- Detected via action keywords: click, select, toggle, enable, disable, choose, check, uncheck, expand, collapse, open, close, tap +- Handles prepositions: "click on `X`", "click the `X`" are also caught +- Keyboard keys stay in backticks (press `Enter`, hit `Esc`) — "press" and "hit" are excluded from the check +- Code-like content (CLI flags, paths, CamelCase identifiers, keyboard shortcuts) is automatically excluded +- Auto-fix with `--fix` converts backtick UI elements to bold + +### Command Palette Names +- Quoted strings near "Command Palette" mentions +- `Command Palette > CommandName` arrow patterns +- Fuzzy matching with suggestions for near-misses + +### Exclusions +- `changelog/` directory (historical record; use `--include-changelog` to opt in) +- `_book/` and `node_modules/` build artifacts +- External product paths (GitHub, Slack, etc.) are filtered by context + +## Auto-Fix + +When run with `--fix`, the script automatically corrects: +- **Case mismatches**: e.g. `Settings > ai` → `Settings > AI` +- **Non-canonical UI path formats**: backtick, italic, bare → per-segment bold +- **Backtick UI elements**: e.g. Click `Save` → Click **Save** +- Only path case fixes with confidence ≥ 0.9 are applied; format fixes are always applied + +Fixes that require manual review (e.g. renamed sections, removed features) are reported but not auto-fixed. + +## Slack Notifications + +Slack notifications are designed for scheduled/automated runs, not ad-hoc usage. When running the skill manually (e.g., during a PR review or docs update), you can review results directly in the terminal output. + +### Current behavior + +The `--slack-notify` flag posts a summary to the configured Slack channel when unfixed issues remain after a run. If the scan is clean (0 issues), no notification is sent. + +### Intended behavior for scheduled runs + +When this skill is configured as a scheduled Oz agent, Slack notifications should alert the team in two cases: + +1. **Auto-fixes applied** — the script found and corrected issues, and created a PR. The notification should include the PR link so the team can review and merge. +2. **Unfixed issues remain** — some issues could not be auto-corrected (e.g., a renamed or removed section) and require manual attention. The notification should list these for triage. + +If a scheduled run finds no issues at all, the notification should be skipped (no noise). + +> **Note:** This two-condition notification logic is not yet implemented. The current `--slack-notify` flag only covers condition 2 (unfixed issues). When we set up scheduled runs, the script should be updated to also notify on condition 1 (auto-fixes with PR link). + +### Setup (one-time) + +Create a Warp team secret for the Slack bot token: + +```bash +oz secret create SLACK_BOT_TOKEN --team --description "Slack bot token for UI ref validation reports" +``` + +The token needs `chat:write` scope. + +### Usage + +```bash +python3 .warp/skills/validate_ui_refs/validate_ui_refs.py --all --slack-notify +``` + +## Cloud Agent / Scheduling + +For scheduled Oz cloud agent runs: + +1. Configure the environment with the docs repo +2. Keep `valid_paths.json` up-to-date by running `--refresh-valid-paths` as a pre-step (requires `warp-internal` in the environment) +3. Set the `SLACK_BOT_TOKEN` secret in the environment +4. Run: `python3 .warp/skills/validate_ui_refs/validate_ui_refs.py --all --fix --create-pr --slack-notify` + +A typical scheduled agent would: +1. Run `--refresh-valid-paths` to update the snapshot +2. Run `--all --fix --create-pr --slack-notify` to check, fix, and report + +## Dependencies + +- Python 3.7+ +- `requests` (for Slack notifications): `pip3 install requests` +- `gh` CLI (for PR creation) +- Access to `warp-internal` repo (only for `--refresh-valid-paths`) diff --git a/.warp/skills/validate_ui_refs/valid_paths.json b/.warp/skills/validate_ui_refs/valid_paths.json new file mode 100644 index 0000000..fd01660 --- /dev/null +++ b/.warp/skills/validate_ui_refs/valid_paths.json @@ -0,0 +1,317 @@ +{ + "settings_sections": { + "About": { + "display_name": "About", + "sub_sections": [], + "source_file": "app/src/settings_view/mod.rs" + }, + "Account": { + "display_name": "Account", + "sub_sections": [], + "source_file": "app/src/settings_view/mod.rs" + }, + "AI": { + "display_name": "AI", + "sub_sections": [ + "Usage", + "Active AI", + "Agents", + "Input", + "MCP Servers", + "Knowledge", + "Voice", + "CLI Agents", + "Experimental", + "API Keys", + "AWS Bedrock" + ], + "source_file": "app/src/settings_view/ai_page.rs" + }, + "Environments": { + "display_name": "Environments", + "sub_sections": [], + "source_file": "app/src/settings_view/mod.rs" + }, + "MCP Servers": { + "display_name": "MCP Servers", + "sub_sections": [], + "source_file": "app/src/settings_view/mod.rs" + }, + "Billing and usage": { + "display_name": "Billing and usage", + "sub_sections": [], + "source_file": "app/src/settings_view/billing_and_usage_page.rs" + }, + "Appearance": { + "display_name": "Appearance", + "sub_sections": [ + "Themes", + "Icon", + "Window", + "Input", + "Panes", + "Blocks", + "Text", + "Cursor", + "Tabs", + "Full-screen Apps" + ], + "source_file": "app/src/settings_view/appearance_page.rs" + }, + "Code": { + "display_name": "Code", + "sub_sections": [], + "source_file": "app/src/settings_view/code_page.rs" + }, + "Features": { + "display_name": "Features", + "sub_sections": [ + "General", + "Session", + "Keys", + "Text Editing", + "Terminal Input", + "Terminal", + "Notifications", + "Workflows", + "System" + ], + "source_file": "app/src/settings_view/features_page.rs" + }, + "Keyboard shortcuts": { + "display_name": "Keyboard shortcuts", + "sub_sections": [], + "source_file": "app/src/settings_view/mod.rs" + }, + "Platform": { + "display_name": "Platform", + "sub_sections": [], + "source_file": "app/src/settings_view/platform_page.rs" + }, + "Privacy": { + "display_name": "Privacy", + "sub_sections": [], + "source_file": "app/src/settings_view/privacy_page.rs" + }, + "Referrals": { + "display_name": "Referrals", + "sub_sections": [], + "source_file": "app/src/settings_view/referrals_page.rs" + }, + "Shared blocks": { + "display_name": "Shared blocks", + "sub_sections": [], + "source_file": "app/src/settings_view/mod.rs" + }, + "Teams": { + "display_name": "Teams", + "sub_sections": [], + "source_file": "app/src/settings_view/teams_page.rs" + }, + "Warpify": { + "display_name": "Warpify", + "sub_sections": [ + "Subshells", + "SSH" + ], + "source_file": "app/src/settings_view/warpify_page.rs" + } + }, + "macos_menu_bar": { + "File": [ + "New Tab", + "New Terminal Tab", + "New Window", + "Close Tab", + "Close Window", + "Launch Configurations" + ], + "View": [ + "Enter Full Screen", + "Exit Full Screen", + "Zoom In", + "Zoom Out", + "Actual Size", + "Toggle Mouse Reporting" + ], + "Warp": [ + "About Warp", + "Settings", + "Check for Updates", + "Quit Warp", + "Warp Drive" + ] + }, + "warp_drive": { + "spaces": [ + "Personal", + "Team", + "Shared" + ], + "object_types": [ + "Rules", + "MCP Servers", + "Notebooks", + "Workflows", + "Prompts", + "Environment Variables", + "Folders" + ] + }, + "command_palette_commands": [ + {"name": "terminal:warpify_subshell", "description": "Warpify subshell"}, + {"name": "terminal:warpify_ssh_session", "description": "Warpify ssh session"}, + {"name": "terminal:accept_prompt_suggestion", "description": "Accept Prompt Suggestion"}, + {"name": "terminal:cancel_command", "description": "Cancel active process"}, + {"name": "terminal:focus_input", "description": "Focus terminal input"}, + {"name": "terminal:paste", "description": "Paste"}, + {"name": "terminal:copy", "description": "Copy"}, + {"name": "terminal:reinput_commands", "description": "Reinput selected commands"}, + {"name": "terminal:reinput_commands_with_sudo", "description": "Reinput selected commands as root"}, + {"name": "terminal:find", "description": "Find in Terminal"}, + {"name": "terminal:select_bookmark_up", "description": "Select the closest bookmark up"}, + {"name": "terminal:select_bookmark_down", "description": "Select the closest bookmark down"}, + {"name": "terminal:open_block_list_context_menu_via_keybinding", "description": "Open block context menu"}, + {"name": "terminal:toggle_teams_modal", "description": "Toggle team workflows modal"}, + {"name": "terminal:copy_git_branch", "description": "Copy git branch"}, + {"name": "terminal:clear_blocks", "description": "Clear Blocks"}, + {"name": "terminal:executing_command_move_cursor_word_left", "description": "Move cursor one word to the left within an executing command"}, + {"name": "terminal:executing_command_move_cursor_word_right", "description": "Move cursor one word to the right within an executing command"}, + {"name": "terminal:executing_command_move_cursor_home", "description": "Move cursor home within an executing command"}, + {"name": "terminal:executing_command_move_cursor_end", "description": "Move cursor end within an executing command"}, + {"name": "terminal:executing_command_delete_word_left", "description": "Delete word left within an executing command"}, + {"name": "terminal:executing_command_delete_line_start", "description": "Delete to line start within an executing command"}, + {"name": "terminal:executing_command_delete_line_end", "description": "Delete to line end within an executing command"}, + {"name": "terminal:backward_tabulation", "description": "Backward tabulation within an executing command"}, + {"name": "terminal:select_previous_block", "description": "Select previous block"}, + {"name": "terminal:select_next_block", "description": "Select next block"}, + {"name": "terminal:open_share_block_modal", "description": "Share selected block"}, + {"name": "terminal:bookmark_selected_block", "description": "Bookmark selected block"}, + {"name": "terminal:find_within_block", "description": "Find within selected block"}, + {"name": "terminal:copy_block", "description": "Copy Command and Output"}, + {"name": "terminal:copy_outputs", "description": "Copy command output"}, + {"name": "terminal:copy_commands", "description": "Copy command"}, + {"name": "terminal:scroll_up_one_line", "description": "Scroll terminal output up one line"}, + {"name": "terminal:scroll_down_one_line", "description": "Scroll terminal output down one line"}, + {"name": "terminal:scroll_to_top_of_selected_block", "description": "Scroll to top of selected block"}, + {"name": "terminal:scroll_to_bottom_of_selected_block", "description": "Scroll to bottom of selected block"}, + {"name": "terminal:select_all_blocks", "description": "Select all blocks"}, + {"name": "terminal:expand_block_selection_above", "description": "Expand selected blocks above"}, + {"name": "terminal:expand_block_selection_below", "description": "Expand selected blocks below"}, + {"name": "terminal:ask_ai_assistant", "description": "Attach Selected Block as Agent Context"}, + {"name": "terminal:ask_ai_assistant_text", "description": "Attach Selected Text as Agent Context"}, + {"name": "terminal:ask_ai_about_selection", "description": "Ask Warp AI about Selection"}, + {"name": "terminal:ask_ai_assistant_last_block", "description": "Ask Warp AI about last block"}, + {"name": "terminal:ask_ai", "description": "Ask Warp AI"}, + {"name": "input:insert_command_correction", "description": "Insert Command Correction"}, + {"name": "terminal:onboarding_flow", "description": "Setup Guide"}, + {"name": "workspace:open_settings_import_page", "description": "Import External Settings"}, + {"name": "terminal:share_current_session", "description": "Share current session"}, + {"name": "terminal:stop_sharing_current_session", "description": "Stop sharing current session"}, + {"name": "terminal:toggle_block_filter", "description": "Toggle block filter on selected or last block"}, + {"name": "terminal:toggle_snackbar_in_active_pane", "description": "Toggle Sticky Command Header in Active Pane"}, + {"name": "terminal:toggle_autoexecute_mode", "description": "Toggle Auto-execute Mode"}, + {"name": "workspace:init_project_rules", "description": "Initiate project for warp"}, + {"name": "terminal:toggle_code_review_pane", "description": "Toggle code review pane"}, + {"name": "workspace:add_current_dir_as_project", "description": "Add current folder as project"}, + {"name": "project_buttons:open_repository", "description": "Open repository"}, + {"name": "project_buttons:create_new_project", "description": "Create new project"}, + {"name": "terminal:set_input_mode_agent", "description": "Set Input Mode to Agent Mode"}, + {"name": "terminal:set_input_mode_terminal", "description": "Set Input Mode to Terminal Mode"}, + {"name": "terminal:toggle_hide_cli_responses", "description": "Toggle Hide CLI Responses"}, + {"name": "workspace:show_theme_chooser", "description": "Open theme picker"}, + {"name": "workspace:activate_first_tab", "description": "Switch to 1st tab"}, + {"name": "workspace:activate_second_tab", "description": "Switch to 2nd tab"}, + {"name": "workspace:activate_third_tab", "description": "Switch to 3rd tab"}, + {"name": "workspace:activate_fourth_tab", "description": "Switch to 4th tab"}, + {"name": "workspace:activate_fifth_tab", "description": "Switch to 5th tab"}, + {"name": "workspace:activate_sixth_tab", "description": "Switch to 6th tab"}, + {"name": "workspace:activate_seventh_tab", "description": "Switch to 7th tab"}, + {"name": "workspace:activate_eighth_tab", "description": "Switch to 8th tab"}, + {"name": "workspace:activate_last_tab", "description": "Switch to last tab"}, + {"name": "workspace:activate_prev_tab", "description": "Activate previous tab"}, + {"name": "workspace:activate_next_tab", "description": "Activate next tab"}, + {"name": "pane_group:navigate_prev", "description": "Activate previous pane"}, + {"name": "pane_group:navigate_next", "description": "Activate next pane"}, + {"name": "workspace:toggle_mouse_reporting", "description": "Toggle Mouse Reporting"}, + {"name": "workspace:create_team_notebook", "description": "Create a new team notebook"}, + {"name": "workspace:create_personal_notebook", "description": "Create a new personal notebook"}, + {"name": "workspace:create_team_workflow", "description": "Create a new team workflow"}, + {"name": "workspace:create_personal_workflow", "description": "Create a new personal workflow"}, + {"name": "workspace:create_team_folder", "description": "Create a new team folder"}, + {"name": "workspace:create_personal_folder", "description": "Create a new personal folder"}, + {"name": "workspace:new_tab", "description": "Create new tab"}, + {"name": "workspace:new_terminal_tab", "description": "Create new terminal tab"}, + {"name": "workspace:toggle_left_panel", "description": "Open Left Panel"}, + {"name": "workspace:toggle_right_panel", "description": "Toggle code review"}, + {"name": "workspace:left_panel_agent_conversations", "description": "Left Panel: Agent conversations"}, + {"name": "workspace:left_panel_project_explorer", "description": "Left Panel: Project explorer"}, + {"name": "workspace:left_panel_global_search", "description": "Left Panel: Global search"}, + {"name": "workspace:left_panel_warp_drive", "description": "Left Panel: Warp Drive"}, + {"name": "workspace:toggle_project_explorer", "description": "Toggle project explorer"}, + {"name": "workspace:toggle_global_search", "description": "Toggle global search"}, + {"name": "workspace:toggle_warp_drive", "description": "Toggle Warp Drive"}, + {"name": "workspace:toggle_conversation_list_view", "description": "Toggle Agent conversation list view"}, + {"name": "workspace:close_panel", "description": "Close focused panel"}, + {"name": "workspace:toggle_command_palette", "description": "Toggle command palette"}, + {"name": "workspace:move_tab_left", "description": "Move tab left"}, + {"name": "workspace:rename_tab", "description": "Rename tab"}, + {"name": "workspace:terminate_app", "description": "Quit Warp"}, + {"name": "workspace:close_window", "description": "Close Window"}, + {"name": "workspace:close_active_tab", "description": "Close the current tab"}, + {"name": "workspace:close_other_tabs", "description": "Close other tabs"}, + {"name": "workspace:close_tabs_right_active_tab", "description": "Close tabs to the right"}, + {"name": "workspace:toggle_notifications_on", "description": "Turn notifications on"}, + {"name": "workspace:toggle_notifications_off", "description": "Turn notifications off"}, + {"name": "workspace:toggle_navigation_palette", "description": "Toggle navigation palette"}, + {"name": "workspace:toggle_launch_config_palette", "description": "Launch configuration palette"}, + {"name": "workspace:toggle_files_palette", "description": "Toggle Files Palette"}, + {"name": "workspace:open_launch_config_save_modal", "description": "Save new launch configuration"}, + {"name": "workspace:search_drive", "description": "Search Warp Drive"}, + {"name": "workspace:update_and_relaunch", "description": "Install update and relaunch"}, + {"name": "workspace:check_for_updates", "description": "Check for updates"}, + {"name": "workspace:log_out", "description": "Log out"}, + {"name": "workspace:toggle_resource_center", "description": "Toggle resource center"}, + {"name": "workspace:export_all_warp_drive_objects", "description": "Export all Warp Drive objects"}, + {"name": "workspace:install_cli", "description": "Install Oz CLI command"}, + {"name": "workspace:uninstall_cli", "description": "Uninstall Oz CLI command"}, + {"name": "workspace:view_changelog", "description": "View latest changelog"}, + {"name": "workspace:toggle_ai_assistant", "description": "New agent pane"}, + {"name": "workspace:toggle_warp_ai", "description": "Toggle Warp AI"}, + {"name": "workspace:create_team_env_vars", "description": "Create new team environment variables"}, + {"name": "workspace:create_personal_env_vars", "description": "Create new personal environment variables"}, + {"name": "workspace:create_personal_ai_prompt", "description": "Create a new personal prompt"}, + {"name": "workspace:create_team_ai_prompt", "description": "Create a new team prompt"}, + {"name": "workspace:shift_focus_left", "description": "Switch Focus to Left Panel"}, + {"name": "workspace:shift_focus_right", "description": "Switch Focus to Right Panel"}, + {"name": "workspace:import_to_personal_drive", "description": "Import To Personal Drive"}, + {"name": "workspace:import_to_team_drive", "description": "Import To Team Drive"}, + {"name": "workspace:open_repository", "description": "Open repository"}, + {"name": "workspace:open_ai_fact_collection", "description": "Open AI Rules"}, + {"name": "workspace:open_mcp_servers", "description": "Open MCP Servers"}, + {"name": "workspace:jump_to_latest_toast", "description": "Jump to latest agent task"}, + {"name": "workspace:open_conversation_history", "description": "Open conversation history"}, + {"name": "workspace:show_settings", "description": "Open Settings"}, + {"name": "workspace:show_settings_account_page", "description": "Open Settings: Account"}, + {"name": "workspace:show_settings_appearance_page", "description": "Open Settings: Appearance"}, + {"name": "workspace:show_settings_features_page", "description": "Open Settings: Features"}, + {"name": "workspace:show_settings_shared_blocks_page", "description": "Open Settings: Shared Blocks"}, + {"name": "workspace:show_settings_keyboard_shortcuts_page", "description": "Open Settings: Keyboard Shortcuts"}, + {"name": "workspace:show_settings_about_page", "description": "Open Settings: About"}, + {"name": "workspace:show_settings_teams_page", "description": "Open Settings: Teams"}, + {"name": "workspace:show_settings_privacy_page", "description": "Open Settings: Privacy"}, + {"name": "workspace:show_settings_warpify_page", "description": "Open Settings: Warpify"}, + {"name": "workspace:show_ai_settings_page", "description": "Open Settings: AI"}, + {"name": "workspace:show_settings_billing_and_usage_page", "description": "Open Settings: Billing and usage"}, + {"name": "workspace:show_settings_code_page", "description": "Open Settings: Code"}, + {"name": "workspace:show_settings_referrals_page", "description": "Open Settings: Referrals"}, + {"name": "workspace:show_settings_environments_page", "description": "Open Settings: Environments"}, + {"name": "workspace:show_mcp_servers_settings_page", "description": "Open Settings: MCP Servers"}, + {"name": "workspace:toggle_agent_management_view", "description": "Toggle the agent management view"}, + {"name": "workspace:show_warp_network_log", "description": "Show Warp Network Log"}, + {"name": "input:exit_vim_insert_mode", "description": "Exit Vim Insert Mode"}, + {"name": "input:toggle_vim_keybindings", "description": "Enable Editing Commands With Vim Keybindings"}, + {"name": "workspace:share_pane", "description": "Share Pane"} + ], + "generated_at": "2026-02-19T20:37:00Z" +} diff --git a/.warp/skills/validate_ui_refs/validate_ui_refs.py b/.warp/skills/validate_ui_refs/validate_ui_refs.py new file mode 100644 index 0000000..6982c00 --- /dev/null +++ b/.warp/skills/validate_ui_refs/validate_ui_refs.py @@ -0,0 +1,1291 @@ +#!/usr/bin/env python3 +"""Validate UI paths and Command Palette names in Warp Astro Starlight documentation. + +Scans markdown files for references to Warp UI paths (Settings > ..., File > ..., etc.) +and Command Palette command names, then validates them against a snapshot of known-valid +paths extracted from the warp-internal codebase. + +Usage: + python3 validate_ui_refs.py --all + python3 validate_ui_refs.py --check-paths + python3 validate_ui_refs.py --check-commands + python3 validate_ui_refs.py --all --fix --create-pr --slack-notify + python3 validate_ui_refs.py --refresh-valid-paths --warp-internal-path /path/to/warp-internal +""" +from __future__ import annotations + +import argparse +import json +import os +import re +import subprocess +import sys +import tempfile +from datetime import datetime, timezone +from difflib import SequenceMatcher +from pathlib import Path +from typing import Any, Dict, List, Optional, Tuple + +# --------------------------------------------------------------------------- +# Constants +# --------------------------------------------------------------------------- + +SCRIPT_DIR = Path(__file__).resolve().parent +DEFAULT_VALID_PATHS_FILE = SCRIPT_DIR / "valid_paths.json" +DEFAULT_DOCS_DIR = SCRIPT_DIR.parents[2] / "docs" +DEFAULT_SLACK_CHANNEL = os.environ.get("SLACK_CHANNEL_ID", "") + +# Known Warp UI roots — paths starting with these are Warp UI paths +WARP_UI_ROOTS = {"Settings", "File", "View", "Warp", "Warp Drive", "Personal"} + +# Roots that belong to external products (not Warp) +EXTERNAL_ROOTS = { + "Mac", "System", "System Preferences", "Windows", "Linux", + "Chrome", "Firefox", "Safari", "VS Code", "Visual Studio", +} + +# Context keywords that indicate a non-Warp UI path even if root matches +EXTERNAL_CONTEXT_KEYWORDS = { + "github", "gitlab", "bitbucket", "organization", "org settings", + "slack", "linear", "notion", "jira", "figma", + "raycast", "vs code", "vscode", "visual studio", +} + +# Known external/OS Settings paths that look like Warp paths but aren't. +# These are matched as prefixes of the normalized path. +EXTERNAL_SETTINGS_PATHS = { + "Settings > Privacy & Security", + "Settings > Secrets and variables", + "Settings > Extensions", + "Settings > Notifications", + "Settings > System", + "Settings > People", + "Settings > General", +} + +# Minimum fuzzy match score to suggest an alternative +FUZZY_MATCH_THRESHOLD = 0.6 + +# Minimum fuzzy match score for auto-fix +AUTO_FIX_THRESHOLD = 0.9 + + +# --------------------------------------------------------------------------- +# Data loading +# --------------------------------------------------------------------------- + +def load_valid_paths(path: Path) -> Dict[str, Any]: + """Load the valid_paths.json snapshot.""" + with open(path, "r") as f: + return json.load(f) + + +# --------------------------------------------------------------------------- +# Extraction: UI paths from docs +# --------------------------------------------------------------------------- + +# Regex patterns for UI paths in various markdown formats +# Backtick: `Settings > AI > Active AI` +RE_BACKTICK_PATH = re.compile( + r"`((?:" + "|".join(re.escape(r) for r in WARP_UI_ROOTS) + r")\s*>\s*[^`]+)`" +) +# Bold: **Settings > AI > Active AI** +RE_BOLD_PATH = re.compile( + r"\*\*((?:" + "|".join(re.escape(r) for r in WARP_UI_ROOTS) + r")\s*>\s*[^*]+)\*\*" +) +# Italic: _Settings > AI > Active AI_ or *Settings > AI* +RE_ITALIC_PATH = re.compile( + r"(?:_|\*)((?:" + "|".join(re.escape(r) for r in WARP_UI_ROOTS) + r")\s*>\s*[^_*]+)(?:_|\*)" +) +# Bare (no formatting): Settings > AI > Active AI (at start of line or after common punctuation) +RE_BARE_PATH = re.compile( + r"(?:^|[(\s])((?:" + "|".join(re.escape(r) for r in WARP_UI_ROOTS) + r")\s*>\s*\S[^.)\n\[,]*)", + re.MULTILINE, +) +# Per-segment backtick: `Settings` > `AI` > `Active AI` +RE_SEG_BACKTICK_PATH = re.compile( + r"(`(?:" + "|".join(re.escape(r) for r in WARP_UI_ROOTS) + r")`\s*>\s*`[^`]+`(?:\s*>\s*`[^`]+`)*)" +) +# Canonical format: **Settings** > **AI** > **Active AI** +RE_CANONICAL_PATH = re.compile( + r"(\*\*(?:" + "|".join(re.escape(r) for r in WARP_UI_ROOTS) + r")\*\*\s*>\s*\*\*[^*]+\*\*(?:\s*>\s*\*\*[^*]+\*\*)*)" +) + + +def _normalize_path(raw: str) -> str: + """Normalize whitespace around > separators and strip artifacts.""" + path = " > ".join(seg.strip() for seg in raw.split(">")) + # Strip trailing punctuation that gets captured by bare-path regex + path = path.rstrip(".,;:!?") + # Strip formatting wrappers from individual segments + segments = path.split(" > ") + segments = [s.strip("`").strip("*") for s in segments] + return " > ".join(segments) + + +def _to_canonical_format(normalized: str) -> str: + """Convert a normalized path to canonical bold format: **Seg** > **Seg**.""" + segments = normalized.split(" > ") + return " > ".join(f"**{seg}**" for seg in segments) + + +def _is_external_path(path: str, line: str) -> bool: + """Check if a path belongs to an external product, not Warp.""" + root = path.split(">")[0].strip() + if root in EXTERNAL_ROOTS: + return True + # Check against known external Settings paths + for ext_path in EXTERNAL_SETTINGS_PATHS: + if path.startswith(ext_path): + return True + # Check surrounding line for external product keywords + line_lower = line.lower() + for kw in EXTERNAL_CONTEXT_KEYWORDS: + if kw in line_lower: + return True + return False + + +def extract_ui_paths(file_path: Path) -> List[Dict[str, Any]]: + """Extract all Warp UI path references from a markdown file.""" + results = [] + try: + text = file_path.read_text(encoding="utf-8") + except (UnicodeDecodeError, OSError): + return results + + for line_num, line in enumerate(text.splitlines(), start=1): + for pattern, fmt in [ + (RE_CANONICAL_PATH, "canonical"), + (RE_SEG_BACKTICK_PATH, "seg_backtick"), + (RE_BACKTICK_PATH, "backtick"), + (RE_BOLD_PATH, "bold"), + (RE_ITALIC_PATH, "italic"), + (RE_BARE_PATH, "bare"), + ]: + for match in pattern.finditer(line): + raw = match.group(1).strip() + normalized = _normalize_path(raw) + if _is_external_path(normalized, line): + continue + # Skip bare paths that look like they captured a full sentence + # (e.g. "Settings > Features so that the completions menu opens") + if fmt == "bare": + segments = normalized.split(" > ") + if len(segments) >= 2 and len(segments[1].split()) > 5: + continue + # Skip if this span was already matched by an earlier pattern + match_span = (line_num, match.start(), match.end()) + if any( + r["_span"] == match_span or + (r["line"] == line_num and r["normalized"] == normalized) + for r in results + ): + continue + results.append({ + "file": str(file_path), + "line": line_num, + "raw": raw, + "normalized": normalized, + "format": fmt, + "match_text": match.group(0), + "line_text": line, + "_span": match_span, + }) + return results + + +# --------------------------------------------------------------------------- +# Extraction: Command Palette names from docs +# --------------------------------------------------------------------------- + +# Patterns for Command Palette references: +# - "Open Theme Picker" near "Command Palette" +# - Command Palette > Open Theme Picker +RE_CMD_PALETTE_QUOTED = re.compile( + r'["\u201c]([^"\u201d\n]{4,})["\u201d]' +) +RE_CMD_PALETTE_ARROW = re.compile( + r"Command Palette\s*>\s*[`\"]*([^`\"\n>]+)[`\"]*" +) + + +# Common words that appear quoted near Command Palette but aren't commands +_CMD_PALETTE_STOPWORDS = { + "macos", "windows", "linux", "mac", "appearance", "export", "share", + "prompt", "a11y", "settings", "preferences", +} + +# UI action keywords that precede toggle/button labels, not CP commands. +# If a quoted string is preceded by one of these on the same line, skip it. +_RE_UI_LABEL_PREFIX = re.compile( + r'\b(toggle|click|clicking|enable|disable|select|check|uncheck)\b', + re.IGNORECASE, +) + + +def _is_plausible_command_name(name: str) -> bool: + """Filter false positives for command palette names.""" + name = name.strip() + # Too short + if len(name) < 4: + return False + # Too long — likely a sentence or alt text, not a command name + if len(name) > 80: + return False + # Pure numbers or special chars + if re.match(r"^[\d\s.,:;!?]+$", name): + return False + # Trailing colon (likely a label, not a command) + if name.endswith(":"): + return False + # Single word (unlikely to be a command name, which are usually multi-word) + if re.match(r"^[A-Za-z]+$", name) and name.lower() in _CMD_PALETTE_STOPWORDS: + return False + # Single lowercase word + if re.match(r"^[a-z]+$", name): + return False + # URLs + if name.startswith("http") or name.startswith("www."): + return False + # File paths or anchors + if "/" in name or "\\" in name or name.startswith("#"): + return False + # Kebab-case strings (URL fragments like "using-forked-conversations") + if re.match(r"^[a-z][a-z0-9-]+$", name): + return False + # HTML/markdown artifacts + if name.startswith("width=") or name.startswith("height="): + return False + if "**" in name or "__" in name: + return False + # Image alt text patterns (long descriptive phrases) + description_indicators = [ + "showing", "displayed", "with the", "interface", "screenshot", + "circled", "button", "view of", "image of", + " ago", # status text like "Completed 10 minutes ago" + ] + name_lower = name.lower() + if any(ind in name_lower for ind in description_indicators): + return False + # OS names that appear near Command Palette mentions + if name_lower in _CMD_PALETTE_STOPWORDS: + return False + # Settings toggle label patterns — typically lowercase descriptive phrases + # that describe a behavior rather than an action command. + # Real commands typically start with a verb: Open, Toggle, Set, Copy, etc. + _settings_toggle_phrases = { + "autocomplete quotes", "autosuggestions", "block dividers", + "compact mode", "copy on select", "cursor blink", + "error underlining for commands", "expand aliases as you type", + "help improve warp", "input hint text", "send crash reports", + "show tab indicators", "show warning before quitting", + "syntax highlighting for commands", "syntax highlighting", + "tab indicators", "show sticky command header", + "settings sync", "empty session", "secret redaction", + "sticky command header", "vim keybindings", + } + if name_lower in _settings_toggle_phrases: + return False + # Ends with common non-command suffixes + if name.endswith(".") or name.endswith("…"): + return False + return True + + +def extract_command_palette_refs(file_path: Path) -> List[Dict[str, Any]]: + """Extract Command Palette command name references from a markdown file.""" + results = [] + try: + text = file_path.read_text(encoding="utf-8") + except (UnicodeDecodeError, OSError): + return results + + lines = text.splitlines() + for line_num, line in enumerate(lines, start=1): + # Check if "Command Palette" is mentioned nearby (within 2 lines) + context_start = max(0, line_num - 3) + context_end = min(len(lines), line_num + 1) + context = " ".join(lines[context_start:context_end]) + has_palette_context = "command palette" in context.lower() + + # Pattern: Command Palette > CommandName + for match in RE_CMD_PALETTE_ARROW.finditer(line): + name = match.group(1).strip() + if _is_plausible_command_name(name): + results.append({ + "file": str(file_path), + "line": line_num, + "name": name, + "pattern": "arrow", + "line_text": line, + }) + + # Pattern: quoted strings near Command Palette mention + if has_palette_context: + for match in RE_CMD_PALETTE_QUOTED.finditer(line): + name = match.group(1).strip() + if _is_plausible_command_name(name): + # Skip if preceded by a UI action keyword (toggle, click, etc.) + # — these are toggle/button labels, not CP commands + prefix = line[:match.start()] + if _RE_UI_LABEL_PREFIX.search(prefix): + continue + # Skip if already captured by arrow pattern + if not any( + r["line"] == line_num and r["name"] == name + for r in results + ): + results.append({ + "file": str(file_path), + "line": line_num, + "name": name, + "pattern": "quoted", + "line_text": line, + }) + + return results + + +# --------------------------------------------------------------------------- +# Validation +# --------------------------------------------------------------------------- + +def _best_fuzzy_match(needle: str, haystack: List[str]) -> Tuple[Optional[str], float]: + """Find the best fuzzy match for needle in haystack.""" + best_match = None + best_score = 0.0 + needle_lower = needle.lower() + for candidate in haystack: + score = SequenceMatcher(None, needle_lower, candidate.lower()).ratio() + if score > best_score: + best_score = score + best_match = candidate + return best_match, best_score + + +def validate_ui_path(path: str, valid_paths: Dict[str, Any]) -> Dict[str, Any]: + """Validate a single UI path against valid_paths data. + + Returns a dict with keys: valid, issue, suggestion, confidence, fix_type. + """ + segments = [s.strip() for s in path.split(">")] + root = segments[0] + + settings = valid_paths.get("settings_sections", {}) + menu_bar = valid_paths.get("macos_menu_bar", {}) + warp_drive = valid_paths.get("warp_drive", {}) + + # --- Settings paths --- + if root == "Settings" and len(segments) >= 2: + section = segments[1] + section_names = list(settings.keys()) + + # Check section (case-insensitive) + exact = section in section_names + if not exact: + ci_match = next( + (s for s in section_names if s.lower() == section.lower()), None + ) + if ci_match: + return { + "valid": False, + "issue": f"Case mismatch: \"{section}\" should be \"{ci_match}\"", + "suggestion": " > ".join(["Settings", ci_match] + segments[2:]), + "confidence": 0.95, + "fix_type": "case_mismatch", + } + best, score = _best_fuzzy_match(section, section_names) + if score >= FUZZY_MATCH_THRESHOLD: + return { + "valid": False, + "issue": f"\"{section}\" is not a known Settings section", + "suggestion": f"Did you mean \"{best}\"? (score: {score:.2f})", + "confidence": score, + "fix_type": "fuzzy" if score >= AUTO_FIX_THRESHOLD else None, + } + return { + "valid": False, + "issue": f"\"{section}\" is not a known Settings section", + "suggestion": f"Valid sections: {', '.join(sorted(section_names))}", + "confidence": 0.0, + "fix_type": None, + } + + # Sub-section validation: only check case mismatches for known sub-sections. + # Individual toggle/setting names beyond the section level are not captured in + # valid_paths.json, so we skip validation for unrecognized sub-sections. + if len(segments) >= 3: + section_data = settings.get(section, {}) + sub_sections = section_data.get("sub_sections", []) + sub = segments[2] + + # Exact match — valid + if sub in sub_sections: + return {"valid": True, "issue": None, "suggestion": None, "confidence": 1.0, "fix_type": None} + + # Case mismatch against a known sub-section — still flag these + if sub_sections: + ci_match = next( + (s for s in sub_sections if s.lower() == sub.lower()), None + ) + if ci_match: + return { + "valid": False, + "issue": f"Case mismatch: \"{sub}\" should be \"{ci_match}\"", + "suggestion": " > ".join(["Settings", section, ci_match] + segments[3:]), + "confidence": 0.95, + "fix_type": "case_mismatch", + } + + # Unrecognized sub-section — skip (likely a toggle/setting name) + return {"valid": True, "issue": None, "suggestion": None, "confidence": 0.8, "fix_type": None} + + return {"valid": True, "issue": None, "suggestion": None, "confidence": 1.0, "fix_type": None} + + # --- macOS menu bar paths --- + if root in ("File", "View", "Warp") and len(segments) >= 2: + menu_items = menu_bar.get(root, []) + item = segments[1] + if item in menu_items: + return {"valid": True, "issue": None, "suggestion": None, "confidence": 1.0, "fix_type": None} + best, score = _best_fuzzy_match(item, menu_items) + if score >= FUZZY_MATCH_THRESHOLD: + return { + "valid": False, + "issue": f"\"{item}\" is not a known {root} menu item", + "suggestion": f"Did you mean \"{best}\"? (score: {score:.2f})", + "confidence": score, + "fix_type": "fuzzy" if score >= AUTO_FIX_THRESHOLD else None, + } + return { + "valid": False, + "issue": f"\"{item}\" is not a known {root} menu item", + "suggestion": f"Valid items: {', '.join(menu_items)}" if menu_items else None, + "confidence": 0.0, + "fix_type": None, + } + + # --- Warp Drive paths --- + if root in ("Warp Drive", "Personal") and len(segments) >= 2: + spaces = warp_drive.get("spaces", []) + object_types = warp_drive.get("object_types", []) + all_valid = spaces + object_types + item = segments[1] + if item in all_valid: + return {"valid": True, "issue": None, "suggestion": None, "confidence": 1.0, "fix_type": None} + best, score = _best_fuzzy_match(item, all_valid) + if score >= FUZZY_MATCH_THRESHOLD: + return { + "valid": False, + "issue": f"\"{item}\" is not a known Warp Drive item", + "suggestion": f"Did you mean \"{best}\"? (score: {score:.2f})", + "confidence": score, + "fix_type": "fuzzy" if score >= AUTO_FIX_THRESHOLD else None, + } + return { + "valid": False, + "issue": f"\"{item}\" is not a known Warp Drive item", + "suggestion": f"Valid items: {', '.join(sorted(all_valid))}", + "confidence": 0.0, + "fix_type": None, + } + + # Single-segment root — valid if it's a known root + if root in WARP_UI_ROOTS and len(segments) == 1: + return {"valid": True, "issue": None, "suggestion": None, "confidence": 1.0, "fix_type": None} + + return {"valid": True, "issue": None, "suggestion": None, "confidence": 0.5, "fix_type": None} + + +def validate_command_name(name: str, valid_paths: Dict[str, Any]) -> Dict[str, Any]: + """Validate a Command Palette name against valid_paths data.""" + commands = valid_paths.get("command_palette_commands", []) + descriptions = [c["description"] for c in commands] + + # Exact match + if name in descriptions: + return {"valid": True, "issue": None, "suggestion": None, "confidence": 1.0} + + # Case-insensitive match + ci_match = next((d for d in descriptions if d.lower() == name.lower()), None) + if ci_match: + return { + "valid": False, + "issue": f"Case mismatch: \"{name}\" should be \"{ci_match}\"", + "suggestion": ci_match, + "confidence": 0.95, + } + + # Fuzzy match + best, score = _best_fuzzy_match(name, descriptions) + if score >= FUZZY_MATCH_THRESHOLD: + return { + "valid": False, + "issue": f"\"{name}\" is not a known Command Palette command", + "suggestion": f"Did you mean \"{best}\"? (score: {score:.2f})", + "confidence": score, + } + + return { + "valid": False, + "issue": f"\"{name}\" is not a known Command Palette command", + "suggestion": None, + "confidence": 0.0, + } + + +# --------------------------------------------------------------------------- +# Format consistency checking +# --------------------------------------------------------------------------- + +# Formats that are NOT canonical +_NON_CANONICAL_FORMATS = {"backtick", "seg_backtick", "bold", "italic", "bare"} + + +def check_format_issues(all_refs: List[Dict[str, Any]]) -> List[Dict[str, Any]]: + """Check extracted UI path refs for non-canonical formatting. + + Canonical format is per-segment bold: **Settings** > **AI** > **Active AI** + """ + issues = [] + for ref in all_refs: + fmt = ref["format"] + if fmt not in _NON_CANONICAL_FORMATS: + continue + canonical = _to_canonical_format(ref["normalized"]) + issues.append({ + "file": ref["file"], + "line": ref["line"], + "raw": ref.get("match_text", ref["raw"]), + "normalized": ref["normalized"], + "format": fmt, + "canonical": canonical, + "line_text": ref["line_text"], + }) + return issues + + +# --------------------------------------------------------------------------- +# UI element format checking +# --------------------------------------------------------------------------- + +# Action keywords that imply a clickable UI element follows. +# "press" and "hit" are excluded — they typically precede keyboard keys. +_UI_ACTION_KEYWORDS = { + "click", "select", "toggle", "enable", "disable", + "choose", "check", "uncheck", "expand", "collapse", + "open", "close", "tap", +} + +# Regex: action keyword followed by backtick-wrapped text. +# Allows optional prepositions/articles between keyword and backtick: +# click `Save`, click on `Save`, click the `Save` button +_RE_ACTION_BACKTICK = re.compile( + r"\b(" + "|".join(_UI_ACTION_KEYWORDS) + r")(?:\s+(?:on|the|a|an))?\s+`([^`]+)`", + re.IGNORECASE, +) + + +# Common keyboard key names that should stay in backticks +_KEYBOARD_KEYS = { + "enter", "return", "tab", "escape", "esc", "space", "backspace", "delete", + "up", "down", "left", "right", "home", "end", "pageup", "pagedown", + "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", + "fn", +} + + +def _is_code_like(text: str) -> bool: + """Return True if backtick content looks like code rather than a UI element.""" + t = text.strip() + # Known keyboard key names + if t.lower() in _KEYBOARD_KEYS: + return True + # CLI flags and options + if t.startswith("-") or t.startswith("--"): + return True + # Slash commands, file paths + if t.startswith("/") or t.startswith("."): + return True + # Environment variables + if t.startswith("$"): + return True + # Contains code-like characters: (), {}, [], = + if re.search(r"[(){}\[\]=]", t): + return True + # Contains underscores (identifiers) or dots (file extensions, methods) + if "_" in t or ("." in t and not t.endswith(".")): + return True + # Contains backtick-unfriendly patterns: looks like a command or path + if re.search(r"\S+/\S+", t): # e.g. owner/repo + return True + # All-uppercase with no spaces likely a key or env var (e.g. RIGHT-CLICK, CMD-ENTER) + if t.replace("-", "").replace("+", "").isupper() and " " not in t: + return True + # Keyboard shortcuts: modifier combos (⌘, ⌥, ⌃, Ctrl+, Cmd+, etc.) + if re.search(r"[⌘⌥⌃⇧↩↑↓←→]", t): + return True + if re.search(r"(?i)(ctrl|cmd|alt|shift|option|meta)[+\-]", t): + return True + # Single character (likely a key) + if len(t) == 1: + return True + # Looks like inline code: contains :: or -> (Rust/C++ style) + if "::" in t or "->" in t: + return True + # CamelCase without spaces (e.g. CloudEnvironment, myFunction) + if " " not in t and re.search(r"[a-z][A-Z]", t): + return True + return False + + +def check_ui_element_format(md_files: List[Path]) -> List[Dict[str, Any]]: + """Find clickable UI elements in backticks that should be bold. + + Detects patterns like: Click `Save` → should be Click **Save** + Excludes code-like content (CLI flags, paths, keyboard shortcuts, etc.). + """ + issues = [] + for md_file in md_files: + try: + text = md_file.read_text(encoding="utf-8") + except (UnicodeDecodeError, OSError): + continue + + in_code_block = False + for line_num, line in enumerate(text.splitlines(), start=1): + # Skip fenced code blocks + stripped = line.strip() + if stripped.startswith("```"): + in_code_block = not in_code_block + continue + if in_code_block: + continue + # Skip HTML comments and hint blocks + if stripped.startswith("<!--") or stripped.startswith("{%"): + continue + + for m in _RE_ACTION_BACKTICK.finditer(line): + element_text = m.group(2).strip() + if _is_code_like(element_text): + continue + raw = f"`{m.group(2)}`" + canonical = f"**{element_text}**" + issues.append({ + "file": str(md_file), + "line": line_num, + "raw": raw, + "normalized": element_text, + "format": "ui_element_backtick", + "canonical": canonical, + "line_text": line, + }) + return issues + + +def apply_format_fixes(format_issues: List[Dict[str, Any]]) -> List[Dict[str, Any]]: + """Apply auto-fixes to convert non-canonical UI path formats to canonical bold.""" + fixes_by_file: Dict[str, List[Dict[str, Any]]] = {} + applied = [] + + for issue in format_issues: + file_path = issue["file"] + fixes_by_file.setdefault(file_path, []).append(issue) + + for file_path, file_issues in fixes_by_file.items(): + try: + text = Path(file_path).read_text(encoding="utf-8") + for issue in file_issues: + old = issue["raw"] + new = issue["canonical"] + if old in text: + text = text.replace(old, new, 1) + applied.append({ + "file": file_path, + "line": issue["line"], + "old": old, + "new": new, + }) + Path(file_path).write_text(text, encoding="utf-8") + except OSError as e: + print(f" Warning: could not fix {file_path}: {e}", file=sys.stderr) + + return applied + + +# --------------------------------------------------------------------------- +# File scanning +# --------------------------------------------------------------------------- + +SKIP_DIRS = {"_book", "node_modules", ".git", "__pycache__"} + + +def scan_docs( + docs_dir: Path, + include_changelog: bool = False, +) -> List[Path]: + """Collect all .md files under docs_dir, excluding skip dirs.""" + files = [] + for md_file in sorted(docs_dir.rglob("*.md")): + # Skip directories + parts = set(md_file.relative_to(docs_dir).parts) + if parts & SKIP_DIRS: + continue + if not include_changelog and "changelog" in parts: + continue + files.append(md_file) + return files + + +# --------------------------------------------------------------------------- +# Auto-fix +# --------------------------------------------------------------------------- + +def apply_fixes(issues: List[Dict[str, Any]]) -> List[Dict[str, Any]]: + """Apply auto-fixes for high-confidence issues. Returns list of applied fixes.""" + fixes_by_file: Dict[str, List[Dict[str, Any]]] = {} + applied = [] + + for issue in issues: + fix_type = issue.get("validation", {}).get("fix_type") + confidence = issue.get("validation", {}).get("confidence", 0) + suggestion = issue.get("validation", {}).get("suggestion") + + if fix_type == "case_mismatch" and confidence >= AUTO_FIX_THRESHOLD and suggestion: + file_path = issue["file"] + fixes_by_file.setdefault(file_path, []).append(issue) + + for file_path, file_issues in fixes_by_file.items(): + try: + text = Path(file_path).read_text(encoding="utf-8") + for issue in file_issues: + old = issue["raw"] + new = issue["validation"]["suggestion"] + if old in text: + text = text.replace(old, new, 1) + applied.append({ + "file": file_path, + "line": issue["line"], + "old": old, + "new": new, + }) + Path(file_path).write_text(text, encoding="utf-8") + except OSError as e: + print(f" Warning: could not fix {file_path}: {e}", file=sys.stderr) + + return applied + + +# --------------------------------------------------------------------------- +# PR creation +# --------------------------------------------------------------------------- + +def create_pr(fixes: List[Dict[str, Any]], repo_root: Path) -> Optional[str]: + """Create a branch and PR with the applied fixes using gh CLI.""" + if not fixes: + print("No fixes to commit.") + return None + + branch = f"fix/ui-refs-{datetime.now(timezone.utc).strftime('%Y%m%d-%H%M%S')}" + try: + subprocess.run(["git", "checkout", "-b", branch], cwd=repo_root, check=True) + subprocess.run(["git", "add", "-A"], cwd=repo_root, check=True) + + files_changed = {f["file"] for f in fixes} + commit_msg = ( + f"docs: fix {len(fixes)} UI reference issue(s)\n\n" + f"Auto-fixed by validate_ui_refs skill.\n" + f"Files changed: {', '.join(sorted(str(Path(f).relative_to(repo_root)) for f in files_changed))}\n\n" + f"Co-Authored-By: Oz <oz-agent@warp.dev>" + ) + subprocess.run(["git", "commit", "-m", commit_msg], cwd=repo_root, check=True) + subprocess.run(["git", "push", "-u", "origin", branch], cwd=repo_root, check=True) + + # Write PR body to a temp file to avoid shell argument length limits + pr_body = ( + f"## Summary\n" + f"Auto-fixed {len(fixes)} UI reference issue(s) found by the `validate_ui_refs` skill.\n\n" + f"## Changes\n" + + "\n".join(f"- `{Path(f['file']).relative_to(repo_root)}` line {f['line']}: " + f"`{f['old']}` → `{f['new']}`" for f in fixes) + + f"\n\nCo-Authored-By: Oz <oz-agent@warp.dev>" + ) + with tempfile.NamedTemporaryFile(mode="w", suffix=".md", delete=False) as tmp: + tmp.write(pr_body) + body_file = tmp.name + + try: + result = subprocess.run( + [ + "gh", "pr", "create", + "--title", f"docs: fix {len(fixes)} UI reference issue(s)", + "--body-file", body_file, + ], + cwd=repo_root, + capture_output=True, + text=True, + ) + finally: + os.unlink(body_file) + if result.returncode == 0: + pr_url = result.stdout.strip() + print(f"PR created: {pr_url}") + return pr_url + else: + print(f"Failed to create PR: {result.stderr}", file=sys.stderr) + return None + + except subprocess.CalledProcessError as e: + print(f"Git error: {e}", file=sys.stderr) + return None + + +# --------------------------------------------------------------------------- +# Slack notification +# --------------------------------------------------------------------------- + +def notify_slack( + report: Dict[str, Any], + channel: str, + pr_url: Optional[str] = None, +) -> bool: + """Post a summary to Slack. Requires SLACK_BOT_TOKEN env var.""" + token = os.environ.get("SLACK_BOT_TOKEN") + if not token: + print("Warning: SLACK_BOT_TOKEN not set, skipping Slack notification.", file=sys.stderr) + return False + + try: + import requests + except ImportError: + print("Warning: requests not installed, skipping Slack notification.", file=sys.stderr) + return False + + path_issues = report.get("path_issues", []) + cmd_issues = report.get("command_issues", []) + fixes = report.get("fixes_applied", []) + + blocks = [ + { + "type": "header", + "text": {"type": "plain_text", "text": "📋 UI Reference Validation Report"}, + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": ( + f"*Files scanned:* {report.get('files_scanned', 0)}\n" + f"*Path issues:* {len(path_issues)}\n" + f"*Command issues:* {len(cmd_issues)}\n" + f"*Auto-fixes applied:* {len(fixes)}" + ), + }, + }, + ] + + if pr_url: + blocks.append({ + "type": "section", + "text": {"type": "mrkdwn", "text": f"*PR:* <{pr_url}|View PR>"}, + }) + + if path_issues: + top_issues = path_issues[:5] + issue_text = "\n".join( + f"• `{Path(i['file']).name}:{i['line']}` — {i['validation']['issue']}" + for i in top_issues + ) + if len(path_issues) > 5: + issue_text += f"\n_...and {len(path_issues) - 5} more_" + blocks.append({ + "type": "section", + "text": {"type": "mrkdwn", "text": f"*Top path issues:*\n{issue_text}"}, + }) + + resp = requests.post( + "https://slack.com/api/chat.postMessage", + headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"}, + json={"channel": channel, "blocks": blocks}, + timeout=10, + ) + data = resp.json() + if resp.ok and data.get("ok"): + print(f"Slack notification sent to channel {channel}.") + return True + else: + error = data.get("error", resp.status_code) + print(f"Slack notification failed: {error}", file=sys.stderr) + return False + + +# --------------------------------------------------------------------------- +# Refresh valid_paths.json from warp-internal +# --------------------------------------------------------------------------- + +def refresh_valid_paths(warp_internal_path: Path, output_path: Path) -> None: + """Re-extract valid paths from warp-internal Rust sources and save to JSON.""" + print(f"Refreshing valid_paths.json from {warp_internal_path}...") + + settings_sections = _extract_settings_sections(warp_internal_path) + command_palette = _extract_command_palette_commands(warp_internal_path) + + # Load existing for menu bar and warp drive (manual lists) + existing = {} + if output_path.exists(): + existing = load_valid_paths(output_path) + + data = { + "settings_sections": settings_sections, + "macos_menu_bar": existing.get("macos_menu_bar", {}), + "warp_drive": existing.get("warp_drive", {}), + "command_palette_commands": command_palette, + "generated_at": datetime.now(timezone.utc).isoformat(), + } + + with open(output_path, "w") as f: + json.dump(data, f, indent=2) + print(f"Wrote {output_path} ({len(settings_sections)} sections, {len(command_palette)} commands)") + + +def _extract_settings_sections(warp_internal: Path) -> Dict[str, Any]: + """Parse SettingsSection enum and sub-sections from Rust source files.""" + mod_rs = warp_internal / "app" / "src" / "settings_view" / "mod.rs" + sections = {} + + # Parse Display impl for section display names + display_map = {} + try: + mod_text = mod_rs.read_text(encoding="utf-8") + except OSError: + print(f"Warning: could not read {mod_rs}", file=sys.stderr) + return sections + + # Extract SettingsSection variants + enum_match = re.search( + r"pub enum SettingsSection\s*\{([^}]+)\}", + mod_text, + re.DOTALL, + ) + if enum_match: + for variant in re.findall(r"(\w+)", enum_match.group(1)): + if variant in ("Copy", "Clone", "Debug", "Default", "PartialEq", "default"): + continue + display_map[variant] = variant # default: use variant name + + # Parse Display impl for overrides + display_impl = re.search( + r"impl Display for SettingsSection\s*\{.*?fn fmt.*?\{(.*?)\}\s*\}", + mod_text, + re.DOTALL, + ) + if display_impl: + for m in re.finditer( + r'SettingsSection::(\w+)\s*=>\s*write!\(f,\s*"([^"]+)"\)', + display_impl.group(1), + ): + display_map[m.group(1)] = m.group(2) + + # Map of source files for sub-sections + page_files = { + "AI": "ai_page.rs", + "Appearance": "appearance_page.rs", + "Features": "features_page.rs", + "Warpify": "warpify_page.rs", + "Code": "code_page.rs", + "Privacy": "privacy_page.rs", + "Platform": "platform_page.rs", + } + + settings_dir = warp_internal / "app" / "src" / "settings_view" + + for variant, display_name in display_map.items(): + source_file = page_files.get(variant, "mod.rs") + sub_sections = [] + + page_path = settings_dir / source_file + if page_path.exists() and source_file != "mod.rs": + try: + page_text = page_path.read_text(encoding="utf-8") + # Extract Category::new("Name", ...) calls + for m in re.finditer(r'Category::new\(\s*"([^"]*)"', page_text): + name = m.group(1) + if name: # skip empty category names + sub_sections.append(name) + # Extract build_sub_header(appearance, "Name", ...) calls + for m in re.finditer(r'build_sub_header\(\s*\w+,\s*"([^"]+)"', page_text): + name = m.group(1) + if name not in sub_sections: + sub_sections.append(name) + except OSError: + pass + + sections[display_name] = { + "display_name": display_name, + "sub_sections": sub_sections, + "source_file": f"app/src/settings_view/{source_file}", + } + + return sections + + +def _extract_command_palette_commands(warp_internal: Path) -> List[Dict[str, str]]: + """Parse EditableBinding registrations to extract command palette commands.""" + commands = [] + seen_descriptions = set() + + source_files = [ + warp_internal / "app" / "src" / "terminal" / "view" / "init.rs", + warp_internal / "app" / "src" / "workspace" / "mod.rs", + ] + + for source_file in source_files: + if not source_file.exists(): + continue + try: + text = source_file.read_text(encoding="utf-8") + except OSError: + continue + + # Pattern: EditableBinding::new("name", "description", ...) + for m in re.finditer( + r'EditableBinding::new\(\s*"([^"]+)",\s*"([^"]+)"', + text, + ): + name, desc = m.group(1), m.group(2) + if desc not in seen_descriptions and not desc.startswith("[Debug]"): + commands.append({"name": name, "description": desc}) + seen_descriptions.add(desc) + + # Pattern: EditableBinding::new("name", BindingDescription::new("description"), ...) + for m in re.finditer( + r'EditableBinding::new\(\s*"([^"]+)",\s*BindingDescription::new\("([^"]+)"\)', + text, + ): + name, desc = m.group(1), m.group(2) + if desc not in seen_descriptions and not desc.startswith("[Debug]"): + commands.append({"name": name, "description": desc}) + seen_descriptions.add(desc) + + return commands + + +# --------------------------------------------------------------------------- +# Report generation +# --------------------------------------------------------------------------- + +def generate_report( + path_issues: List[Dict[str, Any]], + command_issues: List[Dict[str, Any]], + format_issues: List[Dict[str, Any]], + files_scanned: int, + fixes: List[Dict[str, Any]], +) -> str: + """Generate a human-readable text report.""" + now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + lines = [ + f"=== UI REFERENCE VALIDATION REPORT ===", + f"Generated: {now}", + f"Files scanned: {files_scanned}", + "", + ] + + if fixes: + lines.append(f"### AUTO-FIXES APPLIED ({len(fixes)})") + for fix in fixes: + rel = Path(fix["file"]).name + lines.append(f" ✅ {rel}:{fix['line']}") + lines.append(f" {fix['old']} → {fix['new']}") + lines.append("") + + if path_issues: + lines.append(f"### SETTINGS PATH ISSUES ({len(path_issues)} found)") + for issue in path_issues: + rel = Path(issue["file"]).name + validation = issue["validation"] + confidence = validation.get("confidence", 0) + icon = "⚠️" if confidence >= FUZZY_MATCH_THRESHOLD else "❌" + lines.append(f"{icon} {validation['issue']}") + lines.append(f" {rel}:{issue['line']}") + lines.append(f" Path: {issue['normalized']}") + if validation.get("suggestion"): + lines.append(f" Suggestion: {validation['suggestion']}") + lines.append("") + else: + lines.append("### SETTINGS PATH ISSUES (0 found) ✅") + lines.append("") + + if command_issues: + lines.append(f"### COMMAND PALETTE ISSUES ({len(command_issues)} found)") + for issue in command_issues: + rel = Path(issue["file"]).name + validation = issue["validation"] + lines.append(f"❌ UNMATCHED COMMAND") + lines.append(f" {rel}:{issue['line']}") + lines.append(f" Reference: \"{issue['name']}\"") + if validation.get("suggestion"): + lines.append(f" {validation['suggestion']}") + lines.append("") + else: + lines.append("### COMMAND PALETTE ISSUES (0 found) ✅") + lines.append("") + + if format_issues: + lines.append(f"### FORMAT ISSUES ({len(format_issues)} found)") + for issue in format_issues: + rel = Path(issue["file"]).name + lines.append(f"🔧 Non-canonical format ({issue['format']})") + lines.append(f" {rel}:{issue['line']}") + lines.append(f" Found: {issue['raw']}") + lines.append(f" Expected: {issue['canonical']}") + lines.append("") + else: + lines.append("### FORMAT ISSUES (0 found) ✅") + lines.append("") + + return "\n".join(lines) + + +# --------------------------------------------------------------------------- +# Main +# --------------------------------------------------------------------------- + +def main() -> int: + parser = argparse.ArgumentParser( + description="Validate UI paths and Command Palette names in Warp docs." + ) + parser.add_argument("--check-paths", action="store_true", help="Validate Settings menu paths") + parser.add_argument("--check-commands", action="store_true", help="Validate Command Palette names") + parser.add_argument("--check-format", action="store_true", help="Check UI path formatting consistency") + parser.add_argument("--all", action="store_true", help="Run all checks (default)") + parser.add_argument("--fix", action="store_true", help="Auto-fix high-confidence issues") + parser.add_argument("--create-pr", action="store_true", help="Create a PR with fixes") + parser.add_argument("--slack-notify", action="store_true", help="Post results to Slack") + parser.add_argument("--slack-channel", default=DEFAULT_SLACK_CHANNEL, help="Slack channel ID") + parser.add_argument("--include-changelog", action="store_true", help="Include changelog/ in scan") + parser.add_argument("--refresh-valid-paths", action="store_true", help="Re-extract from warp-internal") + parser.add_argument( + "--warp-internal-path", + default=os.environ.get("WARP_INTERNAL_PATH", str(SCRIPT_DIR.parents[2].parent / "warp-internal")), + help="Path to warp-internal repo", + ) + parser.add_argument("--valid-paths", default=str(DEFAULT_VALID_PATHS_FILE), help="Path to valid_paths.json") + parser.add_argument("--docs-dir", default=str(DEFAULT_DOCS_DIR), help="Path to docs directory") + parser.add_argument("--output", help="Save results to JSON file") + + args = parser.parse_args() + + # Default to --all if no check flags specified + if not args.check_paths and not args.check_commands and not args.check_format and not args.refresh_valid_paths: + args.all = True + + valid_paths_file = Path(args.valid_paths) + warp_internal = Path(args.warp_internal_path) + + # Refresh valid paths if requested + if args.refresh_valid_paths: + if not warp_internal.exists(): + print(f"Error: warp-internal not found at {warp_internal}", file=sys.stderr) + return 1 + refresh_valid_paths(warp_internal, valid_paths_file) + if not args.all and not args.check_paths and not args.check_commands: + return 0 + + # Load valid paths + if not valid_paths_file.exists(): + print(f"Error: {valid_paths_file} not found. Run with --refresh-valid-paths first.", file=sys.stderr) + return 1 + valid_paths = load_valid_paths(valid_paths_file) + + # Scan docs + docs_dir = Path(args.docs_dir) + if not docs_dir.exists(): + print(f"Error: docs directory not found at {docs_dir}", file=sys.stderr) + return 1 + + md_files = scan_docs(docs_dir, include_changelog=args.include_changelog) + print(f"Scanning {len(md_files)} markdown files...") + + path_issues = [] + command_issues = [] + format_issues = [] + all_path_refs = [] # All extracted path refs (for format checking) + + for md_file in md_files: + # Extract UI paths (needed for both path validation and format checking) + if args.all or args.check_paths or args.check_format: + refs = extract_ui_paths(md_file) + all_path_refs.extend(refs) + + # Check path validity + if args.all or args.check_paths: + for ref in refs: + validation = validate_ui_path(ref["normalized"], valid_paths) + if not validation["valid"]: + ref["validation"] = validation + path_issues.append(ref) + + # Check Command Palette names + if args.all or args.check_commands: + for ref in extract_command_palette_refs(md_file): + validation = validate_command_name(ref["name"], valid_paths) + if not validation["valid"]: + ref["validation"] = validation + command_issues.append(ref) + + # Check format consistency + if args.all or args.check_format: + format_issues = check_format_issues(all_path_refs) + format_issues.extend(check_ui_element_format(md_files)) + + # Auto-fix + fixes = [] + if args.fix: + if path_issues: + fixes = apply_fixes(path_issues) + fixed_keys = {(f["file"], f["line"]) for f in fixes} + path_issues = [i for i in path_issues if (i["file"], i["line"]) not in fixed_keys] + if format_issues: + format_fixes = apply_format_fixes(format_issues) + fixes.extend(format_fixes) + fixed_keys = {(f["file"], f["line"]) for f in format_fixes} + format_issues = [i for i in format_issues if (i["file"], i["line"]) not in fixed_keys] + + # Generate report + report_text = generate_report(path_issues, command_issues, format_issues, len(md_files), fixes) + print(report_text) + + # Create PR + pr_url = None + if args.create_pr and fixes: + repo_root = SCRIPT_DIR.parents[2] + pr_url = create_pr(fixes, repo_root) + + # Save JSON output + report_data = { + "files_scanned": len(md_files), + "path_issues": path_issues, + "command_issues": command_issues, + "format_issues": format_issues, + "fixes_applied": fixes, + "generated_at": datetime.now(timezone.utc).isoformat(), + } + if args.output: + with open(args.output, "w") as f: + json.dump(report_data, f, indent=2, default=str) + print(f"Results saved to {args.output}") + + # Count remaining (unfixed) issues — used for Slack notification and exit code + total_issues = len(path_issues) + len(command_issues) + len(format_issues) + + # Slack notification (only when issues found) + if args.slack_notify and total_issues > 0: + notify_slack(report_data, args.slack_channel, pr_url) + elif args.slack_notify: + print("No issues found — skipping Slack notification.") + return 1 if total_issues > 0 else 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/.warp/templates/conceptual.md b/.warp/templates/conceptual.md new file mode 100644 index 0000000..0f90858 --- /dev/null +++ b/.warp/templates/conceptual.md @@ -0,0 +1,40 @@ +--- +description: >- + [1-2 sentences: what the concept/feature is + why it matters. + Write as a standalone summary for search results. Lead with user benefit.] +--- + +# [Feature or concept name — sentence case. Title convention: noun or "About [subject]"] + +[Opening paragraph: What this feature/concept is and its primary benefit. +1-3 sentences. Lead with what the user gains from understanding this.] + +## [Key concepts or components — sentence case. Rename to match the subject] + +[Explain the main ideas, components, or building blocks the reader needs +to understand. Use bulleted lists with bold term + dash + description.] + +* **Concept A** - What it is and why it matters. +* **Concept B** - What it is and why it matters. + +## How it works + +[Explain the system behavior, architecture, or data flow. +Focus on "what" and "why" before "how." +Define new terms when they first appear. +Use diagrams or architecture descriptions where they clarify relationships. +IMPORTANT: Do NOT include step-by-step procedures here. +Link to a procedural or quickstart page instead.] + +## When to use [feature name] + +[Decision guidance: when to use this feature and when not to. +Help the reader decide if this is the right tool for their situation.] + +## Related pages + +[Cross-references to related features, procedural guides, and deeper references. +Use descriptive link text.] + +* [Related feature](path/to/page.md) +* [How to configure X](path/to/procedural-page.md) diff --git a/.warp/templates/faq.md b/.warp/templates/faq.md new file mode 100644 index 0000000..73f36bd --- /dev/null +++ b/.warp/templates/faq.md @@ -0,0 +1,29 @@ +--- +description: >- + [1-2 sentences: what topic area these FAQs cover. + Example: "Answers to common questions about Oz cloud agents, billing, and environments."] +--- + +# [Title — sentence case. Title convention: "[Feature] FAQs" or "Frequently asked questions"] + +[Opening paragraph: Brief context about what this FAQ covers and +who it's for. 1-2 sentences.] + +## [Theme group — sentence case. e.g., "General", "Billing", "Configuration"] + +[Group questions by theme so readers can scan for their topic.] + +### [Question in the user's voice? e.g., "Can I use my own API key?" not "BYOK support"] + +[Lead with a direct 1-2 sentence answer. Then provide detail if needed. +Keep answers concise — link to full documentation for deeper topics.] + +### [Another question in the user's voice?] + +[Direct answer first, then detail. Link out for depth.] + +## [Another theme group — sentence case] + +### [Question] + +[Answer] diff --git a/.warp/templates/feature-doc.md b/.warp/templates/feature-doc.md new file mode 100644 index 0000000..01fe19a --- /dev/null +++ b/.warp/templates/feature-doc.md @@ -0,0 +1,64 @@ +--- +description: >- + [1-2 sentences: what the feature does + primary user benefit. + Lead with the benefit, include key terms for SEO.] +--- + +# [Feature name — sentence case, capitalize only the first word and proper feature names] + +[Opening paragraph: What this feature does and its primary benefit. +1-3 sentences. Lead with what the user can accomplish.] + +:::note +[Optional: Key context the reader needs upfront, e.g., when they +DON'T need this feature, or a prerequisite they should know about. +Remove this callout if not needed.] +::: + +## Key features + +[Bulleted list. Bold term + dash + description for each. +Focus on what each capability means for the user.] + +* **Feature A** - What it does and why it matters to the user. +* **Feature B** - What it does and why it matters to the user. + +## How it works + +[CONCEPTUAL section: explain the system behavior, architecture, or flow. +Explain "what" and "why" before "how." +Define new terms when they first appear. +IMPORTANT: Do NOT include step-by-step procedures in this section. +Keep the conceptual and procedural sections clearly separated.] + +## [Usage/configuration section — sentence case. Rename to match the feature, e.g., "Creating environments", "Configuring integrations"] + +[PROCEDURAL section: step-by-step instructions. +Apply all procedural rules from AGENTS.md: +- Motivate steps before giving instructions +- Include expected outcomes after key steps +- Group related actions when they share the same UI context] + +### Prerequisites + +[Bulleted list with inline context for each prerequisite. +Include: what the thing is, where to get it, link to full reference.] + +### [Task name — sentence case. e.g., "Create an environment with the CLI"] + +1. Step description. +2. Step description. +3. Step description. + +## [Additional sections as needed — sentence case. e.g., "Managing X", "Advanced usage"] + +[Repeat the conceptual or procedural pattern as appropriate. +Keep sections clearly delineated by type.] + +## Related pages + +[Cross-references to related features, next steps, deeper references. +Use descriptive link text.] + +* [Related feature](path/to/page.md) +* [Deeper guide](path/to/page.md) diff --git a/.warp/templates/guide-page.md b/.warp/templates/guide-page.md new file mode 100644 index 0000000..6669456 --- /dev/null +++ b/.warp/templates/guide-page.md @@ -0,0 +1,61 @@ +--- +description: >- + [1-2 sentence summary of what this guide covers and what the reader will + achieve. Keep under 160 characters for SEO.] +--- + +# [Task-oriented title in sentence case — reads like a search query] + +[TITLE GUIDANCE: Title should describe what the reader will DO, not what the feature IS. For SEO, capture the non-branded query — write the title a developer would actually search for, not "How to do X in Warp." Good: "How to set up Claude Code". Bad: "How to set up Claude Code in Warp".] + +[One sentence: what you'll accomplish by following this guide. Mention Warp by name. Include a time estimate if possible (e.g., "takes about 10 minutes").] + +import VideoEmbed from '@components/VideoEmbed.astro'; + +<VideoEmbed url="[YouTube or Loom URL — remove this block if no video]" /> + +## Prerequisites + +[List what the reader needs before starting. Include inline context: what each prerequisite is, where to get it, and a link to more info. Orient the reader by naming the application before any menu paths.] + +* **[Prerequisite 1]** — [What it is and where to get it]. See [link to docs] for details. +* **[Prerequisite 2]** — [Brief context]. + +[Use numbered H2 headings for each step (e.g., "## 1. Install Claude Code"). Do not add a "## Steps" wrapper heading — jump straight into the numbered steps after Prerequisites. Motivate each step: explain WHY before HOW, especially for setup steps. End each numbered sub-step with a period. Use ALL_CAPS for placeholder values in commands (e.g., YOUR_API_KEY). Do not use em dashes in procedural or instructional text. If there's an open-source repo for an example, link it. When referencing a Settings path or menu for the first time, orient the reader: "in the Warp app, go to **Settings** > ...".] + +## [Action-oriented step title] + +[Why you're doing this step — 1 sentence of motivation.] + +[Exact prompt, command, or instruction:] + +``` +[prompt or command here] +``` + +[Expected outcome — what should happen after this step.] + +## [Next step title] + +[Motivation + instruction + expected outcome, same pattern as above.] + +## [Final step title] + +[Complete the workflow.] + +## Productivity tips + +[OPTIONAL SECTION — include when the guide naturally leads to workflow improvements. Use this to showcase Warp features (voice, images, vertical tabs, notifications, code review, etc.) as natural extensions of the workflow the reader just completed — not as a separate sales pitch. Remove this section if there are no relevant tips for the guide topic.] + +* **[Tip 1 — feature name]** — [How it improves the workflow the reader just learned. Link to feature docs.] +* **[Tip 2]** — [Same pattern.] + +## Next steps + +[2-3 sentence summary of what the reader accomplished. Then list links to related content. CROSS-LINKING: Always link to at least one other guide in the Guides section and one feature documentation page in the main docs. If this guide relates to features covered in the Coding Agents section (src/content/docs/coding-agents/), link there too. If a standalone summary section feels valuable, add a ## Recap heading above the summary paragraph.] + +* [Link to related guide in the Guides section] +* [Link to relevant feature documentation in the main docs] +* [Link to deeper reference or advanced usage] + +[LINK VERIFICATION: Before publishing, verify every internal link points to an existing page by checking the relevant astro.config.mjs (sidebar config). If a target page is planned but not live, use the closest existing page and add a TODO comment.] diff --git a/.warp/templates/procedural.md b/.warp/templates/procedural.md new file mode 100644 index 0000000..b3147d8 --- /dev/null +++ b/.warp/templates/procedural.md @@ -0,0 +1,51 @@ +--- +description: >- + [1-2 sentences: what the reader will accomplish. + Task-oriented: "Create and manage X" or "Configure Y for Z."] +--- + +# [Task-oriented title — sentence case. Title convention: gerund, e.g., "Configuring X" or "Managing X"] + +[Opening paragraph: What the reader will accomplish and why. +1-2 sentences. Focus on the goal, not the tool.] + +## Prerequisites + +[Only if needed. Bulleted list with inline context for each prerequisite. +Each item should include: what it is (1 short clause), where to get or +create it, and a link to the full reference. +Example: +* **A Warp API key** - Authenticate API requests with a key from + **Settings** > **Platform** in the Warp app. See [API Keys](path) for details.] + +## [Primary task name — sentence case. e.g., "Creating API keys"] + +[Brief motivation: why the reader would do this (1 sentence). +Then numbered steps.] + +1. Step description. +2. Step description. +3. Step description. + +:::note +[Optional: tip, clarification, or "good to know" context +relevant to the steps above.] +::: + +## [Secondary task or follow-up — sentence case. e.g., "Managing API keys"] + +[Repeat the pattern: brief context, then numbered steps or +descriptive content as appropriate.] + +## Troubleshooting + +[Optional but recommended. Common issues the reader might encounter +while following these steps. +Format: symptom/error as bold text, then cause and fix.] + +## Best practices + +[Optional. Bulleted list of actionable recommendations. +Bold the key action at the start of each item.] + +* **Use environment variables** - Avoid passing secrets directly in commands. diff --git a/.warp/templates/quickstart.md b/.warp/templates/quickstart.md new file mode 100644 index 0000000..9adac6c --- /dev/null +++ b/.warp/templates/quickstart.md @@ -0,0 +1,55 @@ +--- +description: >- + [1-2 sentences: what the reader will accomplish + time estimate. + Example: "Learn how to run your first Oz cloud agent in ~10 minutes."] +--- + +# [Descriptive title — sentence case. Title convention: "[Feature] quickstart" or "Quickstart for [product]". Do NOT use a bare "Quickstart" — include the feature name.] + +[Opening paragraph: What the reader will accomplish, who it's for, +and approximately how long it takes (~10 minutes). +1-3 sentences. Keep it brief — this is about speed.] + +*** + +## Prerequisites + +[Minimal. Link to full setup docs rather than inlining lengthy setup. +The reader should be able to start quickly.] + +* **Prerequisite 1** - Brief description with [link to details](path) +* **Prerequisite 2** - Brief description + +*** + +## [Primary workflow — sentence case. e.g., "Running your first cloud agent"] + +_~10 minutes_ + +### 1. Step title + +[Steps can be less formal than full procedural content. +Use heavy visual cues: code blocks, screenshots. +Keep on the critical path — defer edge cases to other pages.] + +### 2. Step title + +### 3. Step title + +*** + +## Next steps + +[2-3 actionable next steps. Always link to conceptual content about the +feature and to deeper procedural guides.] + +* [Deeper guide](path/to/page.md) +* [Related feature](path/to/page.md) + +## Troubleshooting + +[Brief. Only the most common issues someone might hit during the quickstart. +For comprehensive troubleshooting, link to the dedicated page.] + +**Issue description**\ +Cause and fix. diff --git a/.warp/templates/reference.md b/.warp/templates/reference.md new file mode 100644 index 0000000..01a5eea --- /dev/null +++ b/.warp/templates/reference.md @@ -0,0 +1,49 @@ +--- +description: >- + [1-2 sentences: what is documented and how to use this reference. + Example: "Use the Oz CLI to run, configure, and manage agents from the terminal."] +--- + +# [Title — sentence case. Title convention: noun describing contents, e.g., "CLI commands", "Keyboard shortcuts"] + +[Brief intro: what this reference covers and how to use it. +1-2 sentences. This is for lookup, not learning.] + +## [Section name — sentence case. e.g., "Installing the CLI", "Authentication"] + +[Introductory sentence or conceptual context for this section.] + +## [Command/endpoint/option group — sentence case. e.g., "Running agents"] + +[Use a strict repeating pattern for each entry. Every entry must +follow the same structure. Consistency is more important than style. + +For commands/endpoints: name → syntax → description → flags/params → example +For settings/options: name → type → default → description + +Use H2 for major sections, H3 for individual entries. +Use tables for multiple parameters, lists for single elements.] + +### `command-name` + +[Brief description of what this command does.] + +```sh +command-name [options] <required-arg> +``` + +**Key flags:** + +* `--flag-name` (`-f`) — Description of what this flag does. +* `--another-flag` — Description. + +**Example:** + +```sh +command-name --flag-name value +``` + +### `another-command` + +[Repeat the same structure for every entry. +Alphabetize entries where ordering doesn't matter.] diff --git a/.warp/templates/troubleshooting.md b/.warp/templates/troubleshooting.md new file mode 100644 index 0000000..561c394 --- /dev/null +++ b/.warp/templates/troubleshooting.md @@ -0,0 +1,35 @@ +--- +description: >- + [1-2 sentences describing common issues covered on this page. + Example: "Solutions for common issues with Oz cloud agents, environments, and integrations."] +--- + +# [Title — sentence case. Title convention: "Troubleshooting [feature]" or "Known issues with [feature]"] + +:::note +[Optional: link to GitHub issues page, support channels, or related resources.] +For a complete list of issues and feature requests, visit our [GitHub issues page](https://github.com/warpdotdev/Warp/issues). +::: + +## [Category header — sentence case. e.g., "Environments", "Authentication", "CLI"] + +[Group related issues under broad category headers. +Each issue gets its own H3 with the symptom or error message as the header.] + +### [Symptom or error message — use the exact text the user sees] + +[Cause: 1-2 sentences explaining why this happens.] + +[Solution: numbered steps following procedural rules.] + +1. Step to fix the issue. +2. Next step. + +[Workaround (if no full fix is available): +Describe an alternative approach the user can take.] + +### [Another symptom or error message] + +[Repeat the pattern: cause → solution → workaround. +The reader arrived because something broke — lead with the fix, +not background context.] diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..3b29230 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,758 @@ +# Table of Contents +- [Warp Documentation Style Guide](#warp-documentation-style-guide) +- [Warp Docs Repository Guide](#warp-docs-repository-guide) + +# Warp Documentation Style Guide + +This guide establishes standards for writing Warp documentation. It covers voice, formatting, content types, and terminology. Use it as the authoritative reference when creating or updating any page in the Astro Starlight repository. + +## Writing style + +### Voice & tone +- **Professional yet approachable**: Write with authority but remain accessible to developers of all skill levels +- **Direct and action-oriented**: Lead with what users can accomplish, not just what features exist +- **User-focused**: Use second person ("you can", "allows you to") rather than passive voice +- **Confident without jargon**: Explain technical concepts clearly without oversimplifying + +### Language guidelines +- Use consistent terminology throughout (see [Terminology standards](#terminology-standards) and the full glossary in `.warp/references/terminology.md`) +- Em dashes are acceptable for occasional variation in narrative/conceptual text, but use sparingly +- Never use em dashes in procedural or instructional text + +#### Active vs. passive voice +Use active voice whenever possible. Active voice is clearer and more direct. +- ✅ "Warp indexes your codebase to help Agents understand your code." +- ❌ "Your codebase is indexed by Warp to help Agents understand your code." + +Passive voice is acceptable when the action's recipient is more important than the agent, or when the agent is unknown or irrelevant: +- ✅ "A critical security vulnerability was discovered in the authentication module." (emphasis on the vulnerability, not who found it) +- ✅ "The environment is destroyed after the run completes." (the system does this automatically; no human agent) + +#### Ambiguous verbs +When a task is required, use clear, direct verbs. Avoid ambiguous modal verbs like "may," "might," "should," "could," "would," and "can" — these can be interpreted as either a command or a suggestion. +- ✅ "Use `oz agent run` to start a local agent." (required action) +- ✅ "You can optionally specify an Agent Profile." (clearly marked as optional) +- ❌ "You can use `oz agent run` to start a local agent." (is this required or optional?) +- ❌ "You should configure an environment before running cloud agents." (must I, or is it just a suggestion?) + +#### Vague nouns and pronouns +If a pronoun could refer to more than one thing, replace it with the specific noun. +- ✅ "After you merge your pull request, you can delete the branch." +- ❌ "After you merge your pull request, you can delete it." (delete the PR or the branch?) + +#### Stacked modifiers +Avoid strings of nouns that create ambiguity. Use prepositions to clarify relationships. +- ✅ "Default permissions for cloud agents" +- ❌ "Cloud agent default permission settings" + +#### Nominalizations +Avoid turning verbs into nouns. Use the verb form for clearer, shorter sentences. +- ✅ "After the run completes, the container is destroyed." +- ❌ "After the completion of the run, the container undergoes destruction." + +#### Invisible plurals +Avoid words that are ambiguous between singular and plural. +- ✅ "After the file is retrieved, select where to save it." +- ❌ "After file retrieval, select where to save it." (one file or many?) + +### Punctuation and mechanics +- **Serial comma**: Always use it. "Environments, integrations, and schedules" — not "Environments, integrations and schedules." +- **Contractions**: Allowed and encouraged to match our approachable tone. Use "you're," "don't," "it's," "can't." Exception: avoid contractions in error messages or formal warnings. +- **Tense**: Use present tense to describe how things work ("Warp indexes your codebase"). Use imperative for instructions ("Configure your environment"). +- **Person**: Use second person ("you") for instructions. Avoid first person plural ("we") in procedural content. First person is acceptable in conceptual or narrative text when referring to Warp as a company ("We designed Oz to..."). + +### Inclusive language +- Use gender-neutral pronouns ("they/them") for unknown users +- Avoid ableist language ("simple," "easy," "just" — these dismiss the reader's experience) +- Avoid culturally specific idioms or slang that may not translate across regions +- Describe UI elements by name and function, not by appearance alone (supports screen readers and non-visual contexts) + +### Writing for accessibility and agents + +These practices serve both human accessibility needs and AI agent consumption (AEO — Answer Engine Optimization). + +**Accessibility:** +- Include captions or a brief text summary for video embeds so content is accessible without playing the video +- Don't rely on color alone to convey meaning (e.g., "the green status badge"). Always pair color with a text label (e.g., "the **Active** status badge") +- Use header rows in tables. Keep tables simple — avoid deeply nested structures +- Many rules in this guide (active voice, short sentences, plain language, descriptive links, alt text) also serve non-native English speakers and screen reader users + +**Writing for agents (AEO):** +- **Descriptive headers**: Use specific, parseable headers ("Configuring environments") not vague ones ("Getting set up"). Agents use headers as semantic signals to extract answers. +- **Explicit context**: Don't assume the reader arrived from a parent page. State what a thing is before explaining how to use it. This helps agents extract self-contained answers. +- **Frontmatter descriptions**: Agents and search engines use the `description` field to determine relevance before reading the full page. Write descriptions as standalone summaries. +- **Consistent terminology**: Agents struggle when the same concept has multiple names. Use the glossary terms consistently. +- **Machine-parseable patterns**: Consistent list formats, code block labeling, and parameter tables help agents extract structured information. The templates in `.warp/templates/` enforce this. + +## Content structure + +These structural rules apply to all pages regardless of content type. For type-specific page structures, see the templates in `.warp/templates/`. + +### Frontmatter +Every page must include YAML frontmatter with a `description` field. + +```yaml +--- +description: >- + A concise 1-2 sentence summary that explains what the page covers and + what value it provides to the reader. +--- +``` + +Write descriptions as standalone summaries that would make sense in a search result. Lead with the user benefit, include key terms for the topic. +- ✅ `description: Environments ensure your cloud agents run with consistent toolchains across all triggers. Learn when to use environments and how to configure them.` +- ❌ `description: This page describes environments.` + +The `description` field is used as the meta description in search results — write it as a summary that would make someone click. + +### Headers +- Use sentence case for all headers (not title case) +- Proper feature names retain their standard capitalization in headings (e.g., "Admin Panel", "Agent Mode", "Command Palette", "Codebase Context", "Warp Drive"). Sentence case applies to the rest of the heading. + - ✅ `## Accessing the Admin Panel` + - ✅ `## Admin Panel sections` + - ❌ `## Accessing the admin panel` ("Admin Panel" is a proper feature name) +- H1 for page titles only +- H2 for major sections +- H3 for subsections +- Avoid going deeper than H4 + +### File and URL naming +File names become URL slugs in Astro Starlight. Use lowercase, hyphens, and descriptive names that include key terms. +- ✅ `environments.md` → `/environments` +- ✅ `agent-profiles-permissions.md` → `/agent-profiles-permissions` +- ❌ `setup-guide-v2.md`, `new-page.md`, `doc1.md` + +Clean, descriptive URLs rank better in search and are more shareable. + +### Page length and scannability +- Aim for scannable pages. Use clear section headers, short paragraphs (2-4 sentences), and bulleted lists. +- If a page exceeds ~1500 words, consider breaking it into sub-pages or using clear anchor links. +- Avoid thin pages with only a sentence or two — consolidate with related content instead. When two pages cover nearly the same topic, merge them. + +### Opening paragraphs +The first paragraph sets expectations for the entire page. Lead with what the feature does and its primary benefit. +- ✅ "Environments ensure your cloud agents run with the same toolchain and setup every time, regardless of where they're triggered from." +- ❌ "This page explains environments." + +Search engines and AI agents give extra weight to the first paragraph. Lead with the key terms and the user benefit. + +## Formatting standards + +### Lists +- Use bulleted lists for features, benefits, or non-sequential items +- Use numbered lists only for step-by-step processes +- End each numbered step in a procedure with a period +- Bold the key term or feature name at the start of each list item +- Follow the bold term with a dash and explanation + +Example: +```markdown +* **Codebase Context** - Warp indexes your Git-tracked codebase to help Agents understand your code +* **Code Review** - Review, edit, and manage Git diffs in real time +``` + +### Emphasis +Use formatting consistently to distinguish different types of content: +- **Bold** — UI elements, key terms on first use in a list, feature names in context +- *Italic* — introducing a new term inline (not a feature name), titles of external works +- `Backticks` — code, commands, file paths, keyboard keys, config values, CLI flags +- Underline — avoid (poor web accessibility, looks like a link) + +### Code examples +- Always specify the language identifier for syntax highlighting (`bash`, `yaml`, `json`, etc.) +- For terminal commands: use `bash` language. Include `$` prompt only if showing output alongside the command. +- For file contents: use the appropriate language and add a title on the fence, e.g., ` ```yaml title="config.yaml" ` +- For placeholder values in commands, use ALL_CAPS: `export WARP_API_KEY=YOUR_API_KEY` +- Use angle brackets in syntax descriptions: `oz agent run <agent-name>` +- Always explain what a placeholder represents +- Include context about what the code does +- Provide both simple examples and real-world scenarios + +### Images and media +- Always include descriptive alt text (describe what the image shows, not just "screenshot") + - ✅ `alt="Creating a new environment in the Oz Web App"` + - ❌ `alt="screenshot"` or `alt=""` +- Use `<figure>` with `<figcaption>` for images that need captions +- Prefer GIFs for short interactions (under ~15 seconds). Use video embeds for longer demos. +- File naming: lowercase, hyphens, descriptive (`agent-mode-code-diff.png`, not `Screenshot 2026-03-15.png`) +- Store PNGs in `src/assets/<section>/` (Astro optimizes them) and GIFs in `public/assets/<section>/` (to bypass optimization). See the "Assets" section below for the full convention. + +### Links and cross-references +- Use descriptive link text that explains what users will find + - ✅ "Learn more about [Codebase Context](...)" / "See [configuring environments](...)" + - ❌ "Click [here](...)" / "See [this page](...)" +- Cross-reference related features prominently +- Link to external resources when they add value +- Within an Astro Starlight space, use relative paths. For cross-space links, use absolute URLs (`https://docs.warp.dev/...`) +- Descriptive anchor text helps search engines understand page relationships. "Click here" provides no signal; "configuring environments" tells search engines what the linked page is about. + +### Callouts and hints +Use Astro Starlight's hint syntax. Choose the style based on the type of information: + +- `:::note` — supplemental context, tips, "good to know" information +- `:::caution` — caveats, limitations, things that could cause confusion or errors +- `:::danger` — destructive actions, irreversible operations, security implications +- `:::tip` — confirmation of expected outcomes, "you're on the right track" + +```markdown +:::note +For informational context, tips, or additional details +::: + +:::caution +For important caveats, limitations, or things to watch out for +::: +``` + +Use callouts sparingly. A page with 5+ callouts loses its visual impact. + +### Placeholders and dynamic text +- Use ALL_CAPS for placeholder values in commands: `git clone REPO_URL` +- Use angle brackets in syntax descriptions: `oz agent run <agent-name>` +- Use ALL_CAPS for text that changes in the UI: Click **Add** USERNAME **to** REPONAME. +- Always explain what the placeholder represents near where it appears + +### Keys and shortcuts +Keyboard keys and shortcuts use backticks. Use `+` as the separator between keys in a combo. Capitalize only the first letter of each key name (matching keyboard labels). Prefer macOS symbols (`⌘`, `⌥`, `⇧`, `⌃`) when targeting macOS users. +- Single keys: `Enter`, `Esc`, `Tab`, `Space`, `Backspace`, `Delete` +- Arrow keys: `↑`, `↓`, `←`, `→` +- Letter/number keys used as shortcuts: `R`, `E` +- Modifier combos (macOS symbols): `⌘+I`, `⌘+Shift++` +- Modifier combos (spelled out): `Ctrl+G`, `Ctrl+Shift+Enter` +- Cross-platform: `⌘+Shift++` (macOS) or `Ctrl+Shift++` (Windows/Linux) +- Function keys: `F1`, `F12` + +**Rules:** +- Always use backticks, never bold +- Use `+` as separator (not `-`), to avoid ambiguity with the minus/hyphen key +- Capitalize only the first letter: `Ctrl`, `Shift`, `Enter` (not `CTRL`, `SHIFT`, `ENTER`) +- When a `+` key is part of the shortcut, context makes it clear: `⌘+Shift++` means Cmd, Shift, and the plus key + +**Examples:** +- ✅ Press `⌘+I` to switch between command and Agent Mode +- ✅ Open the Code Review panel with `⌘+Shift++` (macOS) or `Ctrl+Shift++` (Windows/Linux) +- ✅ Press `Ctrl+G` to open the rich input editor +- ❌ Press **Enter** (should be `Enter`) +- ❌ `CMD-ENTER` (should be `⌘+Enter` or `Cmd+Enter`) +- ❌ `CTRL+G` (should be `Ctrl+G`) + +### Menu paths +- Bold each UI element in a menu path; leave the > separator plain: **Settings** > **AI** > **Knowledge** +- For macOS menu paths, begin the path with the Apple icon (, Unicode `U+F8FF`). + - **IMPORTANT — preserving the Apple icon**: The `U+F8FF` character is in Unicode's Private Use Area. It renders as the Apple logo only on Apple devices and is **invisible in most editors, terminals, and AI contexts**. It is frequently stripped during edits. When editing any line with a macOS menu path, always verify this character (UTF-8 bytes `EF A3 BF`) is present before the first `>`. If it has been stripped, re-insert it with: `printf '\xEF\xA3\xBF'` +- When referencing a menu path, CLI command, or URL for the first time on a page, orient the reader by identifying the application, website, or tool. Don't assume the reader knows which surface you mean. +- For URLs, name the surface even though the link provides the destination — not all readers will recognize what the URL points to. + +**Use:** +- ✅ **Settings** > **AI** > **Knowledge** +- ✅  > **System Settings** > **Privacy & Security** > **Local Network** +- ✅ In the Warp app, go to **Settings** > **Platform**. +- ✅ In the Oz web app (oz.warp.dev), click **Schedules**. +- ✅ Navigate to the Oz web app at oz.warp.dev/schedules and click **New Schedule**. +- ✅ Find it with `oz environment list` on the Oz CLI or in the [Oz web app](https://oz.warp.dev). + +**Don't use:** +- ❌ `macOS > System Settings > Privacy & Security > Local Network` (code format; use Apple icon, not "macOS") +- ❌ `macOS` > `System Settings` > `Privacy & Security` > `Local Network` (individual backticks; use Apple icon, not "macOS") +- ❌ **macOS > System Settings > Privacy & Security > Local Network** (entire path bolded including separator; use Apple icon, not "macOS") +- ❌ Go to **Settings** > **Platform**. (which app? orient the reader first) +- ❌ Go to oz.warp.dev/schedules and click **New Schedule**. (name the surface before the URL) +- ❌ Find it with `oz environment list`. (what CLI? orient the reader first) +- ❌ **System Settings** > **Privacy & Security** > **Local Network** (macOS path missing the Apple icon — `U+F8FF` must appear before the first `>`) + +### UI elements +- Use bold for interactive UI elements (e.g., buttons, toggles, dropdowns) +- Describe UI elements by name, not just appearance or location. Prefer "In the sidebar, click **Platform**" over "Click the button on the left." +- Format checkbox names in bold. Omit the word "checkbox." Use "select" or "deselect," not "check" or "uncheck." + +**Use:** +- ✅ Click your profile photo in the top-right corner, then click **Settings**. +- ✅ In the sidebar, click **Platform**. + +**Don't use:** +- ❌ In the API Keys section, click `+ Create API Key`. +- ❌ In the API Keys section, click `+ Create API Key`. (use bold, not backticks) +- ❌ Click `Create key`. (use bold, not backticks) + +#### Verbs for UI interactions +Use consistent verbs that match the type of UI element: +- **Click** — buttons, links, tabs, and menu items +- **Enter** — text fields and input boxes +- **Select** — checkboxes, list items, and option choices within a grouped list +- **Choose** — dropdowns, date pickers, and permission levels +- **Toggle** — switches and toggle controls + +**Use:** +- ✅ Click **Save**. +- ✅ Enter a name for the token. +- ✅ Select **read_repository**. +- ✅ Choose an expiration date. +- ✅ Toggle **Dark mode** on. + +**Don't use:** +- ❌ Select **Save**. (use Click for buttons) +- ❌ Set the **Repository** permission to **Read**. (use Choose for permission levels) +- ❌ Check **read_repository**. (use Select for checkboxes) + +## Drafting by content type + +Every documentation page should be drafted according to its content type. Identify the type before you start writing, then follow the structure and rules for that type below. + +### General guidance (all content types) + +These rules apply regardless of content type: + +- **Lead with user benefit**: Open with what the reader can accomplish, not the technical implementation. +- **Orient the reader before UI, CLI, or URL instructions**: When referencing a menu path, CLI command, or URL for the first time on a page, identify the application, website, or tool. Don't assume the reader knows which surface you mean. + - ✅ "In the Warp app, click your profile photo, then go to **Settings** > **Platform**." + - ✅ "In the Oz web app (oz.warp.dev), click **Schedules**." + - ❌ "Go to **Settings** > **Platform**." (which app?) +- **Provide inline context for first references**: Assume the reader arrived directly at this page, not from a parent page. When a prerequisite, concept, or tool is mentioned for the first time, include: what the thing is (1 short clause), where to get or create it, and a link to the full reference. + - ✅ "**A Warp API key** - Authenticate API requests with a key from **Settings** > **Platform** in the Warp app. See the API Keys reference for details." + - ❌ "**An API key** - Create one in **Settings** > **Platform**." (what kind of key? Settings where?) +- **Include practical examples**: Show real-world scenarios, not just toy examples. Concrete examples help the reader understand when and why to use a feature. +- **Cross-reference related pages**: Link to related features, next steps, and deeper references so the reader can continue learning. + +### Conceptual + +**What it is**: Explains what something is, why it exists, and how it works at a high level. + +**When to use**: For pages that help the reader *understand* a topic without guiding them through a specific task. Examples: product overviews, architecture explanations, design philosophy. + +**Structure**: +1. Opening paragraph with what the feature/concept is and its primary benefit +2. Key concepts or components +3. How it works (system behavior, architecture, data flow) +4. When to use it and when not to (decision guidance) +5. Related pages + +**Rules**: +- Explain "what" and "why" before "how" +- Define new terms when they first appear +- Use diagrams or architecture descriptions where they clarify relationships +- Do NOT include step-by-step procedures — link to a procedural or quickstart page instead +- Show real-world scenarios, not just abstract descriptions + +**Existing examples**: `agent-platform/cloud-agents/deployment-patterns.mdx`, `agent-platform/cloud-agents/overview.mdx` + +**Template**: `.warp/templates/conceptual.md` + +### Procedural + +**What it is**: Task-oriented, step-by-step instructions to accomplish a specific goal. + +**When to use**: When the reader needs to *do* something. Examples: configuring an integration, creating an API key, setting up an environment. + +**Structure**: +1. Opening sentence stating what the reader will accomplish +2. Prerequisites (with inline context for each — see General guidance) +3. Numbered steps +4. Expected outcome or confirmation (what success looks like) +5. Troubleshooting for common issues (optional but recommended) + +**Rules**: +- **Keep steps focused, not artificially atomic.** Aim for one primary action per step, but group tightly related actions together when they share the same UI context and doing so keeps the procedure at a readable length. Up to ~3 related actions per step is acceptable. Use judgment: a simple task shouldn't require 10+ steps, but a single step shouldn't be a mini-procedure either. + - Acceptable groupings: actions on the same form (entering a name and choosing an expiration date), a click that reveals the next target (clicking to expand a section, then clicking the revealed item), or a short natural sequence within the same UI area. + - Avoid grouping actions that span different areas of the UI or that would make a step hard to scan at a glance. +- **Motivate steps before giving instructions.** Briefly explain WHY before HOW, especially for setup steps. A single sentence of motivation prevents the reader from wondering "why am I doing this?" + - ✅ "Export your API key so the CLI can authenticate your requests automatically." + - ❌ "Export your API key as an environment variable." (why?) +- Include expected outcomes after key steps so the reader can confirm they're on track. +- Test all instructions for accuracy. +- Provide troubleshooting for common failure points. + +**Existing examples**: `reference/cli/api-keys.mdx`, `agent-platform/cloud-agents/integrations/slack.mdx` + +**Template**: `.warp/templates/procedural.md` + +### Quickstart + +**What it is**: A specialized procedural doc designed to get the reader to a working result fast. Style "quickstart" as one word, lowercase (unless starting a sentence or in a title). + +**When to use**: For first-time experiences with a product area. The reader should go from zero to a working result in ~10 minutes. + +**Structure**: +1. Opening paragraph with what the reader will accomplish and a time estimate +2. Prerequisites (minimal — link to full setup docs rather than inlining lengthy setup) +3. Numbered steps (as few as possible to reach a working result) +4. Next steps (links to deeper guides, advanced usage, related features) + +**Rules**: +- **Give every quickstart a descriptive H1 title.** Don't use a bare "Quickstart" — include the feature or topic name. + - ✅ `# Cloud Agents Quick Start` + - ❌ `# Quickstart` (quickstart for what?) +- Minimize prerequisites — the reader should be able to start quickly. +- Target ~10 minutes or less. +- Keep steps focused on the critical path — defer edge cases and advanced options to other pages. +- All procedural rules apply (focused steps, motivate steps, expected outcomes). + +**Existing examples**: `agent-platform/cloud-agents/quickstart.mdx`, `getting-started/quickstart/installation-and-setup.mdx` + +**Template**: `.warp/templates/quickstart.md` + +### Reference + +**What it is**: Structured factual information for lookup. The reader already knows what they want to do and needs specific details. + +**When to use**: For CLI commands, API endpoints, configuration options, keyboard shortcuts, error codes. + +**Structure**: +1. Brief intro stating what is documented and how to use the reference +2. Syntax or usage pattern +3. Options, parameters, or fields (with descriptions) +4. Examples + +**Rules**: +- Be exhaustive — document every option, flag, and configuration value. +- Use consistent formatting for parameters (e.g., `--flag` in backticks, description as a dash-separated list item). +- Alphabetize entries where ordering doesn't matter. +- Keep descriptions factual and concise — this is for lookup, not learning. +- Include at least one practical example for each command or endpoint. + +**Existing examples**: `reference/cli/index.mdx`, `reference/api-and-sdk/index.mdx` + +**Template**: `.warp/templates/reference.md` + +### Troubleshooting + +**What it is**: Problem → cause → solution format. The reader has encountered an issue and needs to fix it. + +**When to use**: For known issues, common errors, and diagnostic guides. + +**Structure**: +1. Problem or symptom as the header (use the exact error message or a clear description of the symptom) +2. Brief explanation of the cause +3. Solution steps (numbered, following procedural rules) +4. Workaround if a full fix isn't available + +**Rules**: +- Use the problem or error message as the header — this helps with search. +- Group related issues under broader category headers (e.g., "SSH", "Shells"). +- Provide workarounds when a fix isn't available. +- Link to related troubleshooting pages and support channels. + +**Existing examples**: `support-and-community/troubleshooting-and-support/known-issues.mdx`, `reference/cli/troubleshooting.mdx` + +**Template**: `.warp/templates/troubleshooting.md` + +### FAQ + +**What it is**: Question-and-answer format for common questions. + +**When to use**: For pages that collect frequently asked questions about a topic area. + +**Structure**: +```markdown +### Question in the user's voice? +Direct answer with actionable information. Include links to relevant documentation. +``` + +**Rules**: +- Write questions in the user's voice ("Can I use my own API key?" not "BYOK support"). +- Lead with a direct answer, then provide detail. +- Keep answers concise — link to full documentation for deeper topics. +- Group questions by theme (e.g., "General", "Billing", "Errors"). + +**Template**: `.warp/templates/faq.md` + +**Existing examples**: `agent-platform/getting-started/faqs.mdx`, `support-and-community/plans-and-billing/pricing-faqs.mdx` + +### Guide (Guides section) + +**What it is**: A practical, task-oriented walkthrough that helps a developer accomplish a specific goal using Warp. Guides live in the `src/content/docs/university/` directory (the "Guides" Astro Starlight space) and can include video, written steps, or both. + +**When to use**: For educational content that teaches a workflow or use case — not feature documentation (which belongs in the main docs). Guides focus on the "how" with real prompts and reproducible results. + +**Structure**: +1. Frontmatter with `description` (for SEO and search) +2. H1 title — task-oriented, reads like a search query (e.g., "How to Set Up Claude Code" not "Claude Code Setup Tutorial") +3. One-sentence goal — what the reader will accomplish +4. Video embed (if applicable) — kept but not the primary content +5. Prerequisites (if any) +6. Numbered steps with exact prompts/commands +7. Inline explanation of why at decision points. Link to open-source repos when available. +8. Productivity tips (optional) — showcase relevant features as natural workflow extensions +9. "What you achieved" summary at the end with links to related docs + +**Rules**: +- Titles should be task-oriented and scannable. Use shortened titles in the Astro Starlight nav and full descriptive titles in the article H1. +- For SEO: capture the non-branded query when possible. Write the title a developer would actually search for ("How to Set Up Claude Code" not "How to Set Up Claude Code in Warp"). +- All procedural rules apply (focused steps, motivate steps, expected outcomes). +- Link to relevant feature documentation in the main docs where concepts need deeper explanation. +- When a guide has a companion video, the written content should stand alone — a reader should be able to follow the guide without watching the video. + +**Template**: A copyable starting template is available at `.warp/templates/guide-page.md`. Use this when creating new guide pages. + +**Existing examples**: `university/mcp-servers/sentry-mcp-fix-sentry-error-in-empower-website.mdx`, `university/end-to-end-builds/building-a-real-time-chat-app-github-mcp-+-railway.mdx` + + +### Feature documentation (combined pattern) + +This is the most common page type in Warp's docs (~75+ pages). A feature documentation page combines **conceptual** and **procedural** content in one page: it explains what a feature is, then shows how to use it. + +**Structure**: +1. Opening paragraph with what the feature does and its primary benefit +2. Key features list (bulleted, bold term + dash + description) +3. How it works (conceptual — explain the system behavior) +4. Usage or configuration sections (procedural — step-by-step instructions) +5. Related pages + +**Rules**: +- Apply the **conceptual** rules to the explanatory sections (explain what and why, define terms, no procedures in the overview). +- Apply the **procedural** rules to the step-by-step sections (one action per step, motivate steps, expected outcomes). +- Keep the conceptual and procedural sections clearly separated with distinct headers. + +**Existing examples**: `agent-platform/capabilities/skills.mdx`, `agent-platform/cloud-agents/environments.mdx` + +**Template**: `.warp/templates/feature-doc.md` + +## Page templates + +Concrete page scaffolds for each content type are in `.warp/templates/`. Use these as starting points when creating new pages: + +- `.warp/templates/conceptual.md` +- `.warp/templates/procedural.md` +- `.warp/templates/quickstart.md` +- `.warp/templates/reference.md` +- `.warp/templates/troubleshooting.md` +- `.warp/templates/faq.md` +- `.warp/templates/guide-page.md` +- `.warp/templates/feature-doc.md` + +Each template includes inline HTML comments explaining what to put in each section and why. + +## Terminology standards + +Use these terms consistently throughout all documentation. For the full canonical glossary with usage notes, see `.warp/references/terminology.md`. + +### Core features + +Product feature names retain their standard capitalization. Match the exact casing shown in the UI. + +- **Warp** (not "Warp Terminal" unless specifically distinguishing) +- **Agent** or **Agents** (capitalized when referring to Warp's AI agents) +- **Agent Mode** (not "agent mode" or "Agent-mode") +- **Terminal and Agent modes** - The two distinct modes in Warp: terminal mode (for shell commands) and Agent Mode (for multi-turn agent conversations). Use "Terminal and Agent modes" on first reference; use "terminal mode" or "Agent Mode" individually in subsequent references. Do not use "agent modality" or "Agent Modality" — this was an internal name that is not user-facing. +- **Ambient Agents** (capitalized as a feature/section name; lowercase "ambient agents" only when describing the generic concept) +- **Warp Drive** - Shared workspace for saving and organizing commands, workflows, and environment variables across your team. +- **Codebase Context** - Warp indexes your Git-tracked codebase to help Agents understand your code. +- **Admin Panel** - Team management surface for controlling members, roles, and billing. +- **Agent Management Panel** - Interface for viewing and managing running agents (not "agent dashboard" or "agent manager"). + +### Oz terminology + +#### Oz vs Warp +- **Warp** is the terminal and coding surface +- **Oz** is Warp's programmable agent for running and coordinating agents at scale +- There is typically one Warp environment per user session. Oz can run many agents concurrently, across machines, repos, and teams. + +#### Core Oz terms +- **Oz** - Warp's programmable agent for running and coordinating agents at scale +- **Oz agent** - A combination of agent instructions (skill or prompt), trigger (cron, webhook, manual), environment (local, cloud), profile, and host. Agents can be local or cloud, and interactive or ambient. +- **Oz cloud agent** - An Oz agent running in the cloud, from a trigger, schedule, or started from someone's local machine +- **Oz subagent** - A child Oz agent created by a parent Oz agent to parallelize or delegate work +- **Oz run** - A single execution lifecycle of an Oz agent, including actions, outputs, and logs. Always ambient and cloud-based. +- **Oz conversation** - An interactive execution lifecycle within the Warp Terminal, regardless of whether it's local or in the cloud +- **Environment** - The execution context for an Oz agent, including repo access, dependencies, secrets, compute, and runtime configuration +- **Oz dashboard** - The app surface to manage all Oz runs, unified across the Warp app and web +- **Oz web app** - The web app for configuring Oz agents and managing runs + +#### Oz CLI commands +- `oz agent run` - Run a local agent +- `oz agent run-cloud` - Run an adhoc cloud agent +- `oz integration create` - Install integrations (Slack, Linear) +- `oz environment create/list/get/update/delete` - CRUD on environments +- `oz schedule create/list/get/update/delete` - CRUD on scheduled ambient agents +- `oz secret create/list/update/delete` - CRUD on Warp-managed secrets +- `oz run list/get` - Get info on ambient agent runs + +#### Preferred phrases +- ✅ "Ask Oz to..." +- ✅ "Oz can help you..." +- ✅ "What would you like Oz to do?" + +#### Terms to avoid +- ❌ "Ozzies" → Use "Oz agents", "instances", or "Oz subagents" +- ❌ "Deploying an Oz" → Use "Deploying an Oz agent" +- ❌ "The Oz Agent" → Use "An Oz agent" or "A parent Oz agent" +- ❌ "Oz is running" → Use "An Oz agent is running" or "A run is in progress" +- ❌ "AI agents" → Use "agents" (the "AI" prefix is redundant) +- ❌ "Agent Modality" or "agent modality" → Use "Terminal and Agent modes" (this was an internal name, not user-facing) + +### Technical terms +- **AI** (not "A.I.") +- **allowlist** / **denylist** (not "whitelist" / "blocklist") +- **codebase** (one word, lowercase unless part of feature name) +- **command-line** (hyphenated when used as adjective) +- **Git repository** or **repo** (not "git repository") +- **macOS** (not "Mac OS" or "Mac") + +### Billing and credits +- **credits** (lowercase, not "AI credits") - the unit of usage for AI features in Warp +- **Add-on Credits** (capitalized as a product feature name) +- **Cloud Agent Credits** (capitalized as a billing feature name) +- **plan credits** - credits included with a subscription plan +- Use "credit" or "credits" without the "AI" prefix throughout documentation + +### UI elements +- **Settings** (capitalized when referring to the Settings panel) +- **Command Palette** (capitalized) + +## SEO and AEO (AI Engine Optimization) + +All documentation should be written with search discoverability in mind — both for traditional search engines (Google) and AI engines (ChatGPT, Gemini, Perplexity, Copilot). + +### Frontmatter descriptions +- Every page must have a `description` in frontmatter. Write it as a standalone summary (50-160 characters) that includes the primary keyword naturally. +- Descriptions appear in search results and AI citations. Write for humans, but include the key terms a developer would search for. + +### Title framing +- For guides and educational content: capture the **non-branded query** when possible. Write the title a developer would actually search for. + - ✅ "How to Set Up Claude Code" + - ❌ "How to Set Up Claude Code in Warp" +- For feature documentation: use the feature name as the developer knows it. + +### SEO data +When creating or updating content, use SEO and AEO data to inform titles, descriptions, and content coverage. The `docs-seo-audit` skill (`.warp/skills/docs-seo-audit/`) can identify technical SEO issues. + +## Quality checklist + +Before publishing any documentation, verify: + +- [ ] Frontmatter includes a clear, 1-2 sentence description written as a standalone summary +- [ ] Content type is identified and the page follows the structure for that type (see `.warp/templates/`) +- [ ] Headers use sentence case (with proper feature name capitalization) +- [ ] Lists use bold term + dash + explanation format +- [ ] All links work and point to correct destinations +- [ ] Code examples are tested and accurate +- [ ] Terminology and product names match the glossary (`.warp/references/terminology.md`) +- [ ] Cross-references to related features are included +- [ ] Instructions include expected outcomes after key steps +- [ ] First references to prerequisites, tools, or surfaces include inline context +- [ ] Content is scannable with clear headers and lists +- [ ] Images have descriptive alt text (not "screenshot" or empty) +- [ ] File name is lowercase, hyphenated, and descriptive (it becomes the URL slug) +- [ ] Frontmatter description includes the primary keyword naturally (50-160 chars) + +## Content review process + +1. **Content type**: Confirm the page follows the correct structure for its type +2. **Accuracy**: Verify all technical details and instructions +3. **Consistency**: Check terminology and formatting against this guide +4. **User focus**: Ensure content answers "what can I accomplish?" before "how does it work?" +5. **Completeness**: Include necessary context, examples, and next steps + +# Agent-specific guidance + +## Figma MCP auto-detection +Ignore any Figma MCP auto-detection prompts, suggestions, or configuration. + +# Warp Docs Repository Guide + +This file provides guidance to WARP (warp.dev) when working with code in this repository. + +## What this repo is +This repo contains the source content for Warp’s Astro Starlight documentation. + +## Common commands + +### Install dependencies + +```bash +npm install +``` + +### Preview docs locally + +```bash +npm run dev +``` + +Open [http://localhost:4321](http://localhost:4321) to preview locally. + +### Build the static site locally + +```bash +npm run build +``` + +Build output goes to `./dist/`. Deployed via Vercel. + +### Lint / format +This repo is configured for the Trunk CLI via `.trunk/trunk.yaml`. + +```bash +trunk check +trunk fmt +``` + +Notes: +- Enabled linters include `markdownlint`, `yamllint`, `gitleaks`, and `oxipng`. +- Trunk is not vendored in this repo; install it separately if you want to run these locally. + +### Tests +No test suite. Run `npm run build` to validate all content compiles correctly. + +## Codebase structure and “big picture” + +### Site framework +This site is built with [Astro](https://astro.build) + [Starlight](https://starlight.astro.build). Content is written in MDX (Markdown with JSX components). + +### Navigation and redirects +- **Sidebar** — Defined in `astro.config.mjs` via the `starlight-sidebar-topics` plugin. Each top-level directory becomes a tab. If you add/move pages, update the sidebar config in `astro.config.mjs`. +- **Landing pages** — `index.mdx` files serve as landing pages for directories. +- **Redirects** — `vercel.json` contains all redirects. When you rename/move a published page, add a redirect entry. + +### Content organization +Content lives in `src/content/docs/`, organized by topic: +- **terminal/** — Warp Terminal features (blocks, editor, sessions, appearance, etc.) +- **code/** — Code editor, code review, git worktrees +- **getting-started/** — Installation, quickstart, migration +- **knowledge-and-collaboration/** — Warp Drive, teams, admin panel +- **agent-platform/** — Agent Platform (capabilities, local agents, cli agents, cloud agents) +- **reference/** — CLI and API/SDK reference +- **support-and-community/** — Troubleshooting, billing, privacy +- **enterprise/** — Enterprise features, SSO, team management +- **changelog/** — Release changelog +- **university/** — Guides and tutorials + +### Content model +The docs site has multiple levels of hierarchy: +- **Top-level section** (e.g., `src/content/docs/agent-platform/`) + - **Subsections** (e.g., `src/content/docs/agent-platform/capabilities/`) + - **Articles** (e.g., `src/content/docs/agent-platform/capabilities/skills.mdx`) + +We organize content in logical groupings that help people find what they are searching for. We aim to limit the layers of hierarchy, with few nested subcategories, which can make it difficult to find help. + +**Content order**: Organize content predictably in categories and subcategories, from broadest applicability to most specific. General order is: conceptual content, reference content, procedures, troubleshooting information. + +### Assets +- **Static images (PNG)** live in `src/assets/` organized by section (e.g., `src/assets/terminal/`, `src/assets/agent-platform/`). Astro optimizes these at build time. +- **GIFs** live in `public/assets/` (same section structure) to bypass image optimization. +- Reference images using relative paths from content files: `![alt](../../../assets/terminal/image.png)` for PNGs, `![alt](/assets/terminal/animation.gif)` for GIFs. + +### Redirects +All redirects are in `vercel.json` at the repo root. When renaming or moving a page, add a redirect entry. Check the current list before adding to avoid duplicates. + +### Content format +Pages use MDX with Starlight components: +- **Callouts**: `:::note`, `:::tip`, `:::caution`, `:::danger` +- **Tabs**: `<Tabs>` / `<TabItem>` (import from `@astrojs/starlight/components`) +- **Video embeds**: `<VideoEmbed url="..." />` (import from `@components/VideoEmbed.astro`) +- **Steps**: `<Steps>` (import from `@astrojs/starlight/components`) +- **Code blocks**: Standard fenced code blocks with Expressive Code features (titles, line highlighting) + +### Adding pages +1. Create an `.mdx` file in the appropriate directory under `src/content/docs/` +2. Use `index.mdx` for directory landing pages +3. Add the page to the sidebar config in `astro.config.mjs` +4. Add images to `src/assets/` (PNGs) or `public/assets/` (GIFs) + +### Sample doc URLs +Documentation pages are published at `docs.warp.dev/`. For example: +- `docs.warp.dev/terminal/blocks/block-basics` +- `docs.warp.dev/agent-platform/capabilities/skills` +- `docs.warp.dev/reference/cli` + +### OpenAPI spec +`developers/agent-api-openapi.yaml` is the OpenAPI spec for the Warp Agent API. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..3752094 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,142 @@ +# Contributing to Warp Docs + +Thanks for helping improve Warp's documentation. This guide explains how to propose changes, work locally, and open a pull request for review. + +## TL;DR + +* Fork the repository, create a branch, make your changes locally, and open a pull request. +* Open or comment on an issue before starting substantial changes. Small fixes can go straight to a pull request. +* Use an agent if it helps you draft, edit, test, or review the change. +* Run `npm run build` and `npm run typecheck` before opening a pull request. Run `npm run lint` if [Trunk](https://trunk.io/) is installed locally. +* Keep pull requests focused, accurate, and easy to review. + +## How contributing works + +These docs use a standard open-source contribution flow: + +1. Find a docs issue, identify a missing or incorrect page, or notice a small improvement. +2. For substantial changes, open or comment on an issue to align with the docs team before drafting. Substantial changes include new pages, major rewrites, navigation changes, redirects, and content that changes how Warp features are explained. +3. Fork the repository and create a branch for your work. +4. Make the change locally. You can write the docs yourself or use an agent to help draft, edit, and validate the contribution. +5. Run the relevant checks. +6. Open a pull request from your fork. +7. Respond to review feedback from the Warp team. + +Small fixes do not need an issue first. Examples include typo fixes, broken links, outdated screenshots, formatting fixes, and short clarifications. + +## Set up the project + +Install [Node.js](https://nodejs.org/) 20.19+, 22.12+, or 24. These versions match Astro 6's supported runtimes. + +Clone your fork and install dependencies: + +```bash +git clone https://github.com/YOUR_USERNAME/docs.git +cd docs +npm install +``` + +Start the local development server: + +```bash +npm run dev +``` + +Open [http://localhost:4321](http://localhost:4321) to preview the docs site. + +The site runs without local environment variables. To enable optional integrations like the Ask AI button and the "Was this helpful?" widget, copy `.env.example` to `.env` and fill in the public values: + +```bash +cp .env.example .env +``` + +## Work on a change with an agent + +You can use any coding agent to help with a contribution, including Warp's built-in Agent Mode, Claude Code, Codex, Gemini CLI, or another tool. A useful agent workflow is: + +1. Use the repository's included AGENTS.md and related skills. +2. Ask the agent to draft the smallest change that resolves the issue or improves the page. +3. Review the draft or code change yourself for accuracy, tone, and scope. +4. Ask the agent to run available checks and fix any failures. +5. Review the final diff before opening the pull request. +6. If you use an agent to submit a PR on your behalf, ensure the agent uses the repository's pull request template. + +You are responsible for the pull request you submit, even when an agent helped write it. Verify commands, links, screenshots, and product behavior before requesting review. + +## Content guidelines + +Read `AGENTS.md` before drafting or editing docs. It contains the style guide, terminology standards, content type guidance, repository structure, and validation commands used by the Warp docs team. + +Follow these baseline expectations: + +* **Be accurate** - Verify product behavior, commands, UI labels, links, and file paths before publishing. +* **Write for users** - Lead with what the reader can accomplish, then explain how to do it. +* **Use consistent terminology** - Match product names and feature names from `AGENTS.md`. +* **Keep changes scoped** - Avoid mixing unrelated rewrites, formatting changes, and content updates in one pull request. +* **Update navigation when needed** - If you add or move a page, update `astro.config.mjs`. +* **Add redirects when needed** - If you rename or move a published page, add a redirect in `vercel.json`. +* **Use the right asset location** - Put optimized PNGs in `src/assets/` and GIFs in `public/assets/`. + +## Validate your work + +Build the site before opening a pull request: + +```bash +npm run build +``` + +Run typechecking: + +```bash +npm run typecheck +``` + +Run linting if [Trunk](https://trunk.io/) is installed: + +```bash +npm run lint +``` + +Format files if Trunk is installed: + +```bash +npm run fmt +``` + +If a command fails, fix the issue or explain the failure in your pull request description. + +## Open a pull request + +Create a focused pull request from your fork using the repository's [pull request template](https://github.com/warpdotdev/docs/blob/main/.github/PULL_REQUEST_TEMPLATE.md). + +If you're using Warp or Oz to prepare your pull request, the [`create_pr` skill](.warp/skills/create_pr/SKILL.md) can review the branch, format the description, and open the PR for you. + +All pull requests should include a summary of what changed and why, related issues, screenshots when helpful, and known follow-ups or out-of-scope work. + +Keep pull requests small enough to review confidently. If the change affects multiple areas, split it into separate pull requests when possible. + +## Review process + +The Warp docs team reviews pull requests for: + +* **Technical accuracy** - The content matches current product behavior. +* **Reader value** - The change helps users accomplish a task or understand a concept. +* **Style consistency** - The writing follows `AGENTS.md`. +* **Site health** - The build passes, links work, assets render, and navigation is correct. +* **Scope control** - The pull request stays focused on one logical change. + +Reviewers may ask for edits before merging. Respond by pushing updates to the same branch and commenting when the pull request is ready for another look. + +## Code of Conduct + +This project adopts the [Contributor Covenant](https://www.contributor-covenant.org/) (v2.1) as its code of conduct. All contributors and maintainers are expected to follow it in every project space. See Warp's [Code of Conduct](https://github.com/warpdotdev/.github/blob/main/CODE_OF_CONDUCT.md) for the full text, or report violations to warp-coc@warp.dev. + +## Reporting security issues + +See Warp's [security policy](https://github.com/warpdotdev/.github/blob/main/SECURITY.md) for our security disclosure policy and private reporting channels. **Do not open public issues for security vulnerabilities.** + +## Getting help + +* Browse the [Warp docs](https://docs.warp.dev/). +* Join the [Slack Community](https://go.warp.dev/join-preview) to ask questions and connect with other contributors. +* Open a [GitHub issue](https://github.com/warpdotdev/docs/issues) for docs bugs, missing coverage, or suggested improvements. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9496312 --- /dev/null +++ b/README.md @@ -0,0 +1,92 @@ +# Warp Docs + +Source content for [docs.warp.dev](https://docs.warp.dev), the documentation site for [Warp](https://www.warp.dev) and the [Oz](https://oz.warp.dev) agent platform. + +<p align="center"> + <a href="https://www.warp.dev">Website</a> + · + <a href="https://docs.warp.dev">Docs</a> + · + <a href="https://www.warp.dev/code">Code</a> + · + <a href="https://www.warp.dev/agents">Agents</a> + · + <a href="https://github.com/warpdotdev/warp">Warp repo</a> + · + <a href="CONTRIBUTING.md">Contributing</a> +</p> + +## About + +Warp is an agentic development environment, born out of the terminal. This repository contains the public documentation for Warp's terminal, editor, agents, collaboration features, API, and support content. + +The site is built with [Astro](https://astro.build) and [Starlight](https://starlight.astro.build). Content is written in MDX and organized under `src/content/docs/`. + +## Building the project + +Node.js 20.19+, 22.12+, or 24 is required. The supported versions match Astro 6's runtime requirements and are enforced in `package.json`. + +Install dependencies: + +```bash +npm install +``` + +Start the local development server: + +```bash +npm run dev +``` + +Open [http://localhost:4321](http://localhost:4321) to preview the docs site locally. + +## Environment variables + +The site runs without local environment variables. To enable optional integrations like the Ask AI button and the "Was this helpful?" widget, copy `.env.example` to `.env` and fill in the public values: + +```bash +cp .env.example .env +``` + +## Repository structure + +Content lives in `src/content/docs/`, organized by product area: + +* **`terminal/`** - Warp terminal features, including blocks, sessions, editor behavior, and appearance. +* **`code/`** - Code editor, code review, and Git worktree documentation. +* **`getting-started/`** - Installation, quickstarts, migration guides, and onboarding content. +* **`knowledge-and-collaboration/`** - Warp Drive, teams, and Admin Panel documentation. +* **`agent-platform/`** - Agent Platform docs, including agent capabilities, local agents, CLI agents, and cloud agents. +* **`reference/`** - CLI, API, SDK, keyboard shortcut, and technical reference docs. +* **`support-and-community/`** - Troubleshooting, billing, privacy, and support content. +* **`enterprise/`** - Enterprise features, SSO, and team management documentation. +* **`changelog/`** - Public release changelog. +* **`university/`** - Guides and tutorials. + +Sidebar structure is configured in `astro.config.mjs`. Redirects are configured in `vercel.json`. + +## Contributing + +The Warp docs are open source, and contributions are welcome. For substantial changes, open or comment on an issue first so the docs team can align on scope. Small fixes like typo corrections, broken links, and minor clarifications can go straight to a pull request. + +Read [CONTRIBUTING.md](CONTRIBUTING.md) for the full contribution flow, local setup, style expectations, and pull request checklist. + +## Agent skills + +The `.warp/skills/` directory contains [Oz agent skills](https://docs.warp.dev/agent-platform/capabilities/skills) used by the Warp docs team for automated workflows, including style linting, link checking, changelog updates, and terminology syncing. The skills are included for transparency and as examples of how Oz skills can automate documentation workflows. See [`warpdotdev/oz-skills`](https://github.com/warpdotdev/oz-skills) for more examples. + +Some skills depend on internal Warp repositories (`warp-internal`, `warp-server`) and won't run end-to-end without access to those codebases. + +## Support and questions + +* Browse the published [Warp docs](https://docs.warp.dev/). +* Join the [Slack Community](https://go.warp.dev/join-preview) to connect with other users and contributors. +* Open a [GitHub issue](https://github.com/warpdotdev/docs/issues) for docs bugs, missing coverage, or suggested improvements. + +## Code of Conduct and security + +This project follows Warp's [Code of Conduct](https://github.com/warpdotdev/.github/blob/main/CODE_OF_CONDUCT.md). Report security issues through the private channels described in Warp's [security policy](https://github.com/warpdotdev/.github/blob/main/SECURITY.md), not through public issues. + +## License + +Warp Docs is licensed under the [MIT License](LICENSE). diff --git a/astro.config.mjs b/astro.config.mjs new file mode 100644 index 0000000..5a2dcd5 --- /dev/null +++ b/astro.config.mjs @@ -0,0 +1,163 @@ +// @ts-check +import { defineConfig, envField } from 'astro/config'; +import react from '@astrojs/react'; +import sitemap from '@astrojs/sitemap'; +import starlight from '@astrojs/starlight'; +import starlightLlmsTxt from 'starlight-llms-txt'; +import starlightSidebarTopics from 'starlight-sidebar-topics'; +import pageTitleOverride from './src/plugins/page-title-override.ts'; +import vercel from '@astrojs/vercel'; +import { sidebarTopics } from './src/sidebar.ts'; +import docsMarkdownIntegration from './src/integrations/docs-markdown-integration.js'; + +// https://astro.build/config +export default defineConfig({ + site: 'https://docs.warp.dev', + env: { + schema: { + PUBLIC_KAPA_INTEGRATION_ID: envField.string({ + context: 'client', + access: 'public', + optional: true, + }), + PUBLIC_PUSHFEEDBACK_PROJECT_ID: envField.string({ + context: 'client', + access: 'public', + optional: true, + }), + PUBLIC_RUDDERSTACK_WRITE_KEY: envField.string({ + context: 'client', + access: 'public', + optional: true, + }), + // IMPORTANT: If this host ever changes (e.g. switching from the + // app.warp.dev proxy to a direct *.dataplane.rudderstack.com URL), + // the `connect-src` directive in vercel.json must be updated to + // match. A mismatch causes the browser to silently block all + // analytics events with no visible error. + PUBLIC_RUDDERSTACK_DATA_PLANE_URL: envField.string({ + context: 'client', + access: 'public', + optional: true, + }), + }, + }, + integrations: [ + react(), + sitemap(), + starlight({ + // Site title kept as 'Warp' to match the suffix used by the legacy + // GitBook docs (e.g. `<title>Page | Warp` and og:site_name). + title: 'Warp', + logo: { + light: './src/assets/warp-logo-light.svg', + dark: './src/assets/warp-logo-dark.svg', + replacesTitle: true, + }, + editLink: { + baseUrl: 'https://github.com/warpdotdev/docs/edit/main/', + }, + lastUpdated: true, + // Soft-wrap long lines by default. Expressive Code defaults to + // `overflow-x: auto` for `
`, which combined with macOS's
+			// auto-hidden scrollbars made wide lines silently truncate.
+			// `wrap: true` adds the `.wrap` class so EC's `white-space: pre-wrap`
+			// kicks in; leading indents are preserved via its `span.indent` rule.
+			expressiveCode: {
+				defaultProps: {
+					wrap: true,
+				},
+			},
+			head: [
+				// SEO + PWA parity with the legacy GitBook docs. These were emitted
+				// on every page on docs.warp.dev today; Starlight does not produce
+				// them by default. Per-page OG/Twitter tags (image, branded title,
+				// twitter:title/description) live in src/components/CustomHead.astro.
+				//
+				// PushFeedback CSS + JS used to live here, but they were render-
+				// blocking on every page even though the widget itself only sits
+				// at the bottom of the page in `FeedbackFooter.astro`. The lazy
+				// loader now lives inside `FeedbackButtons.astro` and pulls the
+				// assets in `requestIdleCallback` time — off the critical path.
+				{
+					tag: 'meta',
+					attrs: { name: 'robots', content: 'index, follow' },
+				},
+				{
+					tag: 'meta',
+					attrs: { name: 'mobile-web-app-capable', content: 'yes' },
+				},
+				{
+					tag: 'meta',
+					attrs: { name: 'apple-mobile-web-app-capable', content: 'yes' },
+				},
+				{
+					tag: 'meta',
+					attrs: { name: 'apple-mobile-web-app-title', content: 'Warp' },
+				},
+				{
+					tag: 'meta',
+					attrs: { name: 'apple-mobile-web-app-status-bar-style', content: 'black' },
+				},
+				{
+					tag: 'link',
+					attrs: { rel: 'apple-touch-icon', href: '/apple-touch-icon.png' },
+				},
+			],
+			customCss: ['./src/styles/custom.css', './src/styles/warp-components.css', './src/styles/kapa.css'],
+			components: {
+				Head: './src/components/CustomHead.astro',
+				// Header drops the middle Search slot (Scalar-style: search lives
+				// inside the sidebar, see CustomSidebar.astro) and adds the Kapa
+				// "Ask AI" launcher to the right group.
+				Header: './src/components/CustomHeader.astro',
+				// Sidebar prepends Starlight's built-in  as a Scalar-style
+				// pill at the top, then re-renders the topic tabs and default
+				// sidebar nav (replacing starlight-sidebar-topics' own override).
+				Sidebar: './src/components/CustomSidebar.astro',
+				Footer: './src/components/FeedbackFooter.astro',
+				PageTitle: './src/components/CustomPageTitle.astro',
+				PageSidebar: './src/components/CustomPageSidebar.astro',
+				// Inline-SVG SiteTitle override to eliminate logo flicker on full
+				// document navigations (View Transitions are intentionally disabled
+				// — see CustomHead.astro). The override inlines the logo SVGs in
+				// HTML so the logo paints in the same frame as the rest of the
+				// header, instead of arriving a few frames late as an  decode.
+				SiteTitle: './src/components/CustomSiteTitle.astro',
+			},
+			routeMiddleware: './src/routeData.ts',
+			social: [
+				{ icon: 'github', label: 'GitHub', href: 'https://github.com/warpdotdev' },
+			],
+			plugins: [
+				starlightSidebarTopics(sidebarTopics),
+				pageTitleOverride(),
+				// Generates /llms.txt, /llms-full.txt, /llms-small.txt at build time.
+				// Restores parity with the legacy GitBook docs which served
+				// /llms.txt and /llms-full.txt; /llms-full.txt alone had ~310k
+				// impressions / 115 clicks in GSC over the last 90 days and is
+				// widely consumed by AI agents.
+				starlightLlmsTxt({
+					projectName: 'Warp',
+					description:
+						'Documentation for Warp, the agentic development environment, and Oz, Warp\'s programmable agent for running and coordinating agents at scale.',
+					customSets: [
+						{ label: 'Terminal', description: 'Warp Terminal features and configuration.', paths: ['terminal/**'] },
+						{ label: 'Agent Platform', description: 'Warp\'s Agent Platform: capabilities, local agents, CLI agents, cloud agents.', paths: ['agent-platform/**'] },
+						{ label: 'Code', description: 'Code editor, code review, and Git worktrees.', paths: ['code/**'] },
+						{ label: 'Enterprise', description: 'Enterprise features, SSO, team management, and security.', paths: ['enterprise/**'] },
+						{ label: 'Getting Started', description: 'Installation, quickstart, and migration guides.', paths: ['getting-started/**'] },
+						{ label: 'Knowledge and Collaboration', description: 'Warp Drive, teams, and the Admin Panel.', paths: ['knowledge-and-collaboration/**'] },
+						{ label: 'Reference', description: 'CLI and API reference.', paths: ['reference/**'] },
+						{ label: 'Support', description: 'Troubleshooting, billing, and privacy.', paths: ['support-and-community/**'] },
+						{ label: 'Guides (Warp University)', description: 'Task-oriented walkthroughs.', paths: ['university/**'] },
+					],
+				}),
+			],
+		}),
+		docsMarkdownIntegration(),
+	],
+	adapter: vercel({
+		edgeMiddleware: true,
+	}),
+});
diff --git a/developers/agent-api-openapi.yaml b/developers/agent-api-openapi.yaml
new file mode 100644
index 0000000..cd2bc4b
--- /dev/null
+++ b/developers/agent-api-openapi.yaml
@@ -0,0 +1,3518 @@
+openapi: 3.0.0
+info:
+  title: Oz Agent API
+  version: 1.0.0
+  description: |
+    API for creating, managing, and querying Oz cloud agent runs.
+    
+    These endpoints allow users to programmatically spawn agents, list runs, 
+    and retrieve detailed run information.
+  contact:
+    name: Warp Support
+    url: https://docs.warp.dev
+    email: support@warp.dev
+  license:
+    name: Proprietary
+servers:
+  - url: https://app.warp.dev/api/v1
+    description: Warp Server
+
+tags:
+  - name: agent
+    description: Operations for running and managing cloud agents
+  - name: schedules
+    description: Operations for creating and managing scheduled agents
+
+paths:
+  /agent:
+    get:
+      summary: List available agents
+      description: |
+        Retrieve a list of available agents (skills) that can be used to run tasks.
+        Agents are discovered from environments or a specific repository.
+      operationId: listAgents
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: repo
+          in: query
+          description: |
+            Optional repository specification to list agents from (format: "owner/repo").
+            If not provided, lists agents from all accessible environments.
+          required: false
+          schema:
+            type: string
+        - name: refresh
+          in: query
+          description: |
+            When true, clears the agent list cache before fetching.
+            Use this to force a refresh of the available agents.
+          required: false
+          schema:
+            type: boolean
+            default: false
+        - name: sort_by
+          in: query
+          description: |
+            Sort order for the returned agents.
+            - "name": Sort alphabetically by name (default)
+            - "last_run": Sort by most recently used
+          required: false
+          schema:
+            type: string
+            enum:
+              - name
+              - last_run
+        - name: include_malformed_skills
+          in: query
+          description: |
+            When true, includes skills whose SKILL.md file exists but is
+            malformed. These variants will have a non-empty `error` field
+            describing the parse failure. Defaults to false.
+          required: false
+          schema:
+            type: boolean
+            default: false
+      responses:
+        '200':
+          description: List of available agents
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ListAgentsResponse'
+        '400':
+          description: Invalid repository specification
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+  /agent/runs/{runId}/transcript:
+    get:
+      summary: Get run transcript
+      description: |
+        Retrieve the raw conversation transcript for an agent run.
+        Returns a 302 redirect to a time-limited download URL for the transcript.
+      operationId: getRunTranscript
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: runId
+          in: path
+          description: The unique identifier of the run
+          required: true
+          schema:
+            type: string
+      responses:
+        '302':
+          description: Redirect to a download URL for the transcript
+          headers:
+            Location:
+              description: URL to download the transcript
+              schema:
+                type: string
+                format: uri
+        '400':
+          description: Missing run ID
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: No permission to access run transcript
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '404':
+          description: Run not found or has no transcript
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '500':
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+  /agent/run:
+    post:
+      summary: Run an agent task
+      description: |
+        Spawn a cloud agent with a prompt and optional configuration.
+        The agent will be queued for execution and assigned a unique run ID.
+      operationId: runAgent
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/RunAgentRequest'
+            examples:
+              simple:
+                summary: Simple prompt
+                value:
+                  prompt: "Fix the bug in auth.go"
+              withConfig:
+                summary: With agent config
+                value:
+                  prompt: "Refactor the database layer"
+                  config:
+                    name: "my-agent"
+                    model_id: "gpt-5-4-high"
+                    base_prompt: "Focus on Go backend code"
+                  title: "DB Refactoring Run"
+      responses:
+        '200':
+          description: Run created successfully
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/RunAgentResponse'
+        '400':
+          description: Invalid request (missing prompt, invalid config)
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: No permission to access referenced resources (environment, MCP servers)
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+  /agent/runs:
+    post:
+      summary: Run an agent task (preferred)
+      description: |
+        Alias for POST /agent/run. This is the preferred endpoint for creating
+        new agent runs. Behavior is identical to POST /agent/run.
+      operationId: createRun
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/RunAgentRequest'
+      responses:
+        '200':
+          description: Run created successfully
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/RunAgentResponse'
+        '400':
+          description: Invalid request (missing prompt, invalid config)
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: No permission to access referenced resources (environment, MCP servers)
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+    get:
+      summary: List agent runs
+      description: |
+        Retrieve a paginated list of agent runs with optional filtering.
+        Results default to `sort_by=updated_at` and `sort_order=desc`.
+      operationId: listRuns
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: limit
+          in: query
+          description: Maximum number of runs to return
+          required: false
+          schema:
+            type: integer
+            minimum: 1
+            maximum: 500
+            default: 20
+        - name: cursor
+          in: query
+          description: Pagination cursor from previous response
+          required: false
+          schema:
+            type: string
+        - name: sort_by
+          in: query
+          description: |
+            Sort field for results.
+            - `updated_at`: Sort by last update timestamp (default)
+            - `created_at`: Sort by creation timestamp
+            - `title`: Sort alphabetically by run title
+            - `agent`: Sort alphabetically by skill. Runs without a skill are grouped last.
+          required: false
+          schema:
+            type: string
+            enum:
+              - updated_at
+              - created_at
+              - title
+              - agent
+            default: updated_at
+        - name: sort_order
+          in: query
+          description: Sort direction
+          required: false
+          schema:
+            type: string
+            enum:
+              - asc
+              - desc
+            default: desc
+        - name: state
+          in: query
+          description: |
+            Filter by run state. Can be specified multiple times to match any of the given states.
+          required: false
+          schema:
+            type: array
+            items:
+              $ref: '#/components/schemas/RunState'
+          style: form
+          explode: true
+        - name: name
+          in: query
+          description: Filter by agent config name
+          required: false
+          schema:
+            type: string
+        - name: model_id
+          in: query
+          description: Filter by model ID
+          required: false
+          schema:
+            type: string
+        - name: creator
+          in: query
+          description: Filter by creator UID (user or service account)
+          required: false
+          schema:
+            type: string
+        - name: source
+          in: query
+          description: Filter by run source type
+          required: false
+          schema:
+            $ref: '#/components/schemas/RunSourceType'
+        - name: execution_location
+          in: query
+          description: Filter by where the run executed
+          required: false
+          schema:
+            $ref: '#/components/schemas/RunExecutionLocation'
+        - name: created_after
+          in: query
+          description: Filter runs created after this timestamp (RFC3339 format)
+          required: false
+          schema:
+            type: string
+            format: date-time
+        - name: created_before
+          in: query
+          description: Filter runs created before this timestamp (RFC3339 format)
+          required: false
+          schema:
+            type: string
+            format: date-time
+        - name: updated_after
+          in: query
+          description: Filter runs updated after this timestamp (RFC3339 format)
+          required: false
+          schema:
+            type: string
+            format: date-time
+        - name: environment_id
+          in: query
+          description: Filter runs by environment ID
+          required: false
+          schema:
+            type: string
+        - name: skill
+          in: query
+          description: |
+            Filter runs by skill spec (e.g., "owner/repo:path/to/SKILL.md").
+            Alias for skill_spec.
+          required: false
+          schema:
+            type: string
+        - name: skill_spec
+          in: query
+          description: Filter runs by skill spec (e.g., "owner/repo:path/to/SKILL.md")
+          required: false
+          schema:
+            type: string
+        - name: schedule_id
+          in: query
+          description: Filter runs by the scheduled agent ID that created them
+          required: false
+          schema:
+            type: string
+        - name: ancestor_run_id
+          in: query
+          description: Filter runs by ancestor run ID. The referenced run must exist and be accessible to the caller.
+          required: false
+          schema:
+            type: string
+        - name: artifact_type
+          in: query
+          description: Filter runs by artifact type
+          required: false
+          schema:
+            type: string
+            enum:
+              - PLAN
+              - PULL_REQUEST
+              - SCREENSHOT
+              - FILE
+        - name: q
+          in: query
+          description: Fuzzy search query across run title, prompt, and skill_spec
+          required: false
+          schema:
+            type: string
+      responses:
+        '200':
+          description: List of runs
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ListRunsResponse'
+        '400':
+          description: Invalid request parameters
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+  /agent/runs/{runId}:
+    get:
+      summary: Get run details
+      description: |
+        Retrieve detailed information about a specific agent run, 
+        including the full prompt, session link, and resolved configuration.
+      operationId: getRun
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: runId
+          in: path
+          description: The unique identifier of the run
+          required: true
+          schema:
+            type: string
+      responses:
+        '200':
+          description: Run details
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/RunItem'
+        '400':
+          description: Missing run ID
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: No permission to access run
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '404':
+          description: Run not found
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+  /agent/runs/{runId}/conversation:
+    get:
+      summary: Get normalized run conversation
+      description: |
+        Retrieve a run's conversation as a normalized sequence of messages and
+        nested steps.
+        The response groups text, tool activity, and event content into
+        structured blocks.
+      operationId: getRunConversation
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: runId
+          in: path
+          description: The unique identifier of the run
+          required: true
+          schema:
+            type: string
+      responses:
+        '200':
+          description: Normalized conversation
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ConversationResponse'
+        '400':
+          description: Missing run ID
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: No permission to access run
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '404':
+          description: Run not found, or the run has no conversation
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '422':
+          description: |
+            Conversation format is not yet supported by the normalized endpoint
+            (error_code: operation_not_supported)
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+  /agent/runs/{runId}/cancel:
+    post:
+      summary: Cancel a run
+      description: |
+        Cancel an agent run that is currently queued or in progress.
+        Once cancelled, the run will transition to a cancelled state.
+
+        Not all runs can be cancelled. Runs that are in a terminal state
+        (SUCCEEDED, FAILED, ERROR, BLOCKED, CANCELLED) return 400. Runs in
+        PENDING state return 409 (retry after a moment). Self-hosted, local,
+        and GitHub Action runs return 422.
+      operationId: cancelRun
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: runId
+          in: path
+          description: The unique identifier of the run to cancel
+          required: true
+          schema:
+            type: string
+      responses:
+        '200':
+          description: Run cancelled successfully
+          content:
+            application/json:
+              schema:
+                type: string
+                description: The ID of the cancelled run
+        '400':
+          description: |
+            Missing run ID, or the run is already in a terminal state
+            (error_code: invalid_request)
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: No permission to cancel run
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '404':
+          description: Run not found
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '409':
+          description: |
+            Run is in PENDING state and cannot be cancelled yet.
+            Retry after a moment (error_code: conflict, retryable: true).
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '422':
+          description: |
+            Run cannot be cancelled because the operation is not supported
+            for this run type (e.g., self-hosted, local, or GitHub Action runs)
+            (error_code: operation_not_supported)
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+  /agent/conversations/{conversation_id}:
+    get:
+      summary: Get normalized conversation
+      description: |
+        Retrieve a conversation directly by conversation ID in Warp's
+        normalized task/message format.
+      operationId: getConversation
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: conversation_id
+          in: path
+          description: The unique identifier of the conversation
+          required: true
+          schema:
+            type: string
+      responses:
+        '200':
+          description: Normalized conversation
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ConversationResponse'
+        '400':
+          description: Missing conversation ID
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: No permission to access conversation
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '404':
+          description: Conversation not found
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '422':
+          description: |
+            Conversation format is not yet supported by the normalized endpoint
+            (error_code: operation_not_supported)
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+  /agent/messages:
+    post:
+      summary: Send a message to one or more runs
+      description: |
+        Send a point-to-point message to one or more agent runs.
+        Each recipient gets an independent message row with its own delivery state.
+        Requires the OrchestrationV2 feature flag.
+      operationId: sendAgentMessage
+      x-internal: true
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              type: object
+              required:
+                - to
+                - subject
+                - body
+                - sender_run_id
+              properties:
+                to:
+                  type: array
+                  items:
+                    type: string
+                  description: List of recipient run IDs
+                subject:
+                  type: string
+                  maxLength: 1024
+                  description: Message subject
+                body:
+                  type: string
+                  maxLength: 131072
+                  description: Message body (max 128KB)
+                sender_run_id:
+                  type: string
+                  description: The sender's run ID
+      responses:
+        '200':
+          description: Message sent successfully
+          content:
+            application/json:
+              schema:
+                type: object
+                properties:
+                  message_ids:
+                    type: array
+                    items:
+                      type: string
+                    description: One message ID per recipient, in the same order as the to array
+        '422':
+          description: One or more recipients are in a terminal state
+
+  /agent/messages/{runId}:
+    get:
+      summary: List inbox message headers
+      operationId: listAgentMessages
+      x-internal: true
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: runId
+          in: path
+          required: true
+          schema:
+            type: string
+        - name: unread
+          in: query
+          schema:
+            type: boolean
+        - name: since
+          in: query
+          schema:
+            type: string
+            format: date-time
+        - name: limit
+          in: query
+          schema:
+            type: integer
+            default: 50
+            maximum: 100
+      responses:
+        '200':
+          description: List of message headers
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  type: object
+                  properties:
+                    message_id:
+                      type: string
+                    sender_run_id:
+                      type: string
+                    subject:
+                      type: string
+                    sent_at:
+                      type: string
+                      format: date-time
+                    delivered_at:
+                      type: string
+                      format: date-time
+                      nullable: true
+                    read_at:
+                      type: string
+                      format: date-time
+                      nullable: true
+
+  /agent/messages/{messageId}/read:
+    post:
+      summary: Read a message body
+      description: Returns the full message body and sets read_at.
+      operationId: readAgentMessage
+      x-internal: true
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: messageId
+          in: path
+          required: true
+          schema:
+            type: string
+      responses:
+        '200':
+          description: Full message content
+          content:
+            application/json:
+              schema:
+                type: object
+                properties:
+                  message_id:
+                    type: string
+                  sender_run_id:
+                    type: string
+                  subject:
+                    type: string
+                  body:
+                    type: string
+                  sent_at:
+                    type: string
+                    format: date-time
+                  delivered_at:
+                    type: string
+                    format: date-time
+                    nullable: true
+                  read_at:
+                    type: string
+                    format: date-time
+                    nullable: true
+
+  /agent/messages/{messageId}/delivered:
+    post:
+      summary: Mark a message as delivered
+      description: Sets delivered_at if not already set. Idempotent.
+      operationId: markAgentMessageDelivered
+      x-internal: true
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: messageId
+          in: path
+          required: true
+          schema:
+            type: string
+      responses:
+        '204':
+          description: Delivered
+
+  /agent/events:
+    get:
+      summary: Poll for events
+      description: |
+        Batch poll for events across multiple watched runs.
+        Returns events ordered by monotonic sequence number.
+        Client advances the cursor (since parameter) on each poll.
+      operationId: pollAgentEvents
+      x-internal: true
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: run_ids
+          in: query
+          required: true
+          style: form
+          explode: true
+          schema:
+            type: array
+            items:
+              type: string
+        - name: since
+          in: query
+          schema:
+            type: integer
+            format: int64
+            default: 0
+        - name: limit
+          in: query
+          schema:
+            type: integer
+            default: 100
+            maximum: 500
+      responses:
+        '200':
+          description: List of events
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  type: object
+                  properties:
+                    event_type:
+                      type: string
+                    run_id:
+                      type: string
+                    ref_id:
+                      type: string
+                      nullable: true
+                    execution_id:
+                      type: string
+                      nullable: true
+                    occurred_at:
+                      type: string
+                      format: date-time
+                    sequence:
+                      type: integer
+                      format: int64
+
+  /agent/events/{runId}:
+    post:
+      summary: Report a lifecycle event
+      description: |
+        Client reports a lifecycle event for a run.
+        This is the canonical mechanism for all lifecycle events.
+      operationId: reportAgentEvent
+      x-internal: true
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: runId
+          in: path
+          required: true
+          schema:
+            type: string
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              type: object
+              required:
+                - event_type
+              properties:
+                event_type:
+                  type: string
+                  enum:
+                    - run_in_progress
+                    - run_succeeded
+                    - run_failed
+                    - run_errored
+                    - run_blocked
+                    - run_cancelled
+                execution_id:
+                  type: string
+                  description: Client-assigned execution ID for correlation
+                ref_id:
+                  type: string
+                  description: Event-type-specific reference (e.g., message ID for new_message events)
+      responses:
+        '200':
+          description: Event recorded
+          content:
+            application/json:
+              schema:
+                type: object
+                properties:
+                  sequence:
+                    type: integer
+                    format: int64
+
+  /agent/schedules:
+    post:
+      summary: Create a scheduled agent
+      description: |
+        Create a new scheduled agent that runs on a cron schedule.
+        The agent will be triggered automatically based on the cron expression.
+      operationId: createScheduledAgent
+      tags:
+        - schedules
+      security:
+        - bearerAuth: []
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/CreateScheduledAgentRequest'
+            examples:
+              simple:
+                summary: Simple daily schedule
+                value:
+                  name: "Daily Code Review"
+                  cron_schedule: "0 9 * * *"
+                  prompt: "Review open pull requests and provide feedback"
+                  enabled: true
+              withConfig:
+                summary: With agent config
+                value:
+                  name: "Weekly Report"
+                  cron_schedule: "0 10 * * 1"
+                  prompt: "Generate weekly status report"
+                  enabled: true
+                  agent_config:
+                    model_id: "claude-4-6-opus-high"
+      responses:
+        '201':
+          description: Scheduled agent created successfully
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ScheduledAgentItem'
+        '400':
+          description: Invalid request (missing required fields, invalid cron expression)
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: No permission or feature not available
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+    get:
+      summary: List scheduled agents
+      description: |
+        Retrieve all scheduled agents accessible to the authenticated user.
+        Results are sorted alphabetically by name.
+      operationId: listScheduledAgents
+      tags:
+        - schedules
+      security:
+        - bearerAuth: []
+      responses:
+        '200':
+          description: List of scheduled agents
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ListScheduledAgentsResponse'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '500':
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+  /agent/schedules/{scheduleId}:
+    get:
+      summary: Get scheduled agent details
+      description: |
+        Retrieve detailed information about a specific scheduled agent,
+        including its configuration, history, and next scheduled run time.
+      operationId: getScheduledAgent
+      tags:
+        - schedules
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: scheduleId
+          in: path
+          description: The unique identifier of the scheduled agent
+          required: true
+          schema:
+            type: string
+      responses:
+        '200':
+          description: Scheduled agent details
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ScheduledAgentItem'
+        '400':
+          description: Missing schedule ID
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: No permission to access schedule
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '404':
+          description: Schedule not found
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+    put:
+      summary: Update a scheduled agent
+      description: |
+        Update an existing scheduled agent's configuration.
+        All fields except agent_config are required.
+      operationId: updateScheduledAgent
+      tags:
+        - schedules
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: scheduleId
+          in: path
+          description: The unique identifier of the scheduled agent
+          required: true
+          schema:
+            type: string
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/UpdateScheduledAgentRequest'
+      responses:
+        '200':
+          description: Scheduled agent updated successfully
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ScheduledAgentItem'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: No permission to update schedule
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '404':
+          description: Schedule not found
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+    delete:
+      summary: Delete a scheduled agent
+      description: |
+        Delete a scheduled agent. This will stop all future scheduled runs.
+      operationId: deleteScheduledAgent
+      tags:
+        - schedules
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: scheduleId
+          in: path
+          description: The unique identifier of the scheduled agent
+          required: true
+          schema:
+            type: string
+      responses:
+        '200':
+          description: Scheduled agent deleted successfully
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/DeleteScheduledAgentResponse'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: No permission to delete schedule
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '404':
+          description: Schedule not found
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '500':
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+  /agent/schedules/{scheduleId}/pause:
+    post:
+      summary: Pause a scheduled agent
+      description: |
+        Pause a scheduled agent. The agent will not run until resumed.
+      operationId: pauseScheduledAgent
+      tags:
+        - schedules
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: scheduleId
+          in: path
+          description: The unique identifier of the scheduled agent
+          required: true
+          schema:
+            type: string
+      responses:
+        '200':
+          description: Scheduled agent paused successfully
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ScheduledAgentItem'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: No permission to pause schedule
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '404':
+          description: Schedule not found
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '500':
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+  /agent/schedules/{scheduleId}/resume:
+    post:
+      summary: Resume a scheduled agent
+      description: |
+        Resume a paused scheduled agent. The agent will start running
+        according to its cron schedule.
+      operationId: resumeScheduledAgent
+      tags:
+        - schedules
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: scheduleId
+          in: path
+          description: The unique identifier of the scheduled agent
+          required: true
+          schema:
+            type: string
+      responses:
+        '200':
+          description: Scheduled agent resumed successfully
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ScheduledAgentItem'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: No permission to resume schedule
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '404':
+          description: Schedule not found
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '500':
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+  /agent/environments:
+    get:
+      summary: List environments
+      description: |
+        Retrieve cloud environments accessible to the authenticated principal.
+        Returns environments the caller owns, has been granted guest access to,
+        or has accessed via link sharing.
+      operationId: listEnvironments
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: sort_by
+          in: query
+          required: false
+          description: |
+            Sort order for the returned environments.
+            - `name`: alphabetical by environment name
+            - `last_updated`: most recently updated first (default)
+          schema:
+            type: string
+            enum:
+              - name
+              - last_updated
+            default: last_updated
+      responses:
+        '200':
+          description: List of accessible environments
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ListEnvironmentsResponse'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '500':
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+  /agent/models:
+    get:
+      summary: List available models
+      description: |
+        Retrieve the list of LLM models available to the authenticated user for
+        agent runs. The response includes which model is the default, as well as
+        per-model metadata such as provider, cost, and whether the model is
+        currently disabled (and why).
+      operationId: listModels
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      responses:
+        '200':
+          description: List of available models
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ListModelsResponse'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '500':
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+  /agent/artifacts/{artifactUid}:
+    get:
+      summary: Get artifact details
+      description: |
+        Retrieve an artifact by its UUID. For downloadable file-like artifacts,
+        returns a time-limited signed download URL. For plan artifacts, returns
+        the current plan content inline.
+      operationId: getArtifact
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: artifactUid
+          in: path
+          description: The unique identifier (UUID) of the artifact
+          required: true
+          schema:
+            type: string
+      responses:
+        '200':
+          description: Artifact details with download information
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ArtifactResponse'
+        '400':
+          description: Missing artifact UID
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: No permission to access artifact
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '404':
+          description: Artifact not found or unsupported artifact type
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+  /agent/identities:
+    post:
+      summary: Create an agent
+      description: |
+        Create a new agent for the caller's team.
+        Agents can be used as the execution principal for team-owned runs.
+      operationId: createAgent
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/CreateAgentRequest'
+      responses:
+        '201':
+          description: Agent created successfully
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/AgentResponse'
+        '400':
+          description: Invalid request (empty name, user on multiple teams, or on no team)
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: Only human users can manage agents, or plan limit exceeded
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '500':
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+    get:
+      summary: List agents
+      description: |
+        List all agents for the caller's team. Each agent includes
+        an `available` flag indicating whether it is within the team's plan limit
+        and may be used for runs.
+      operationId: listAgents
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      responses:
+        '200':
+          description: List of agents
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ListAgentIdentitiesResponse'
+        '400':
+          description: User on multiple teams, or on no team
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: Only human users can list agents
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '500':
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+  /agent/identities/{uid}:
+    put:
+      summary: Update an agent
+      description: |
+        Update an existing agent.
+      operationId: updateAgent
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: uid
+          in: path
+          description: The unique identifier of the agent
+          required: true
+          schema:
+            type: string
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/UpdateAgentRequest'
+      responses:
+        '200':
+          description: Agent updated successfully
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/AgentResponse'
+        '400':
+          description: Missing or invalid request body
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: Only human users can manage agents, or plan limit exceeded
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '404':
+          description: Agent not found
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '500':
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+    delete:
+      summary: Delete an agent
+      description: |
+        Delete an agent. All API keys associated with the
+        agent are deleted atomically.
+      operationId: deleteAgent
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: uid
+          in: path
+          description: The unique identifier of the agent
+          required: true
+          schema:
+            type: string
+      responses:
+        '204':
+          description: Agent deleted successfully
+        '400':
+          description: Cannot delete the default agent
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '401':
+          description: Authentication required
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '403':
+          description: Only human users can manage agents
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '404':
+          description: Agent not found
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+        '500':
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+  /agent/sessions/{sessionUuid}/redirect:
+    get:
+      summary: Get session redirect
+      description: |
+        Check whether a shared session should redirect to a conversation transcript.
+        Returns a conversation_id if the agent sandbox has finished and conversation
+        data is available, or an empty object if no redirect is needed.
+      operationId: getSessionRedirect
+      tags:
+        - agent
+      security:
+        - bearerAuth: []
+      parameters:
+        - name: sessionUuid
+          in: path
+          description: The UUID of the shared session
+          required: true
+          schema:
+            type: string
+      responses:
+        '200':
+          description: |
+            Redirect information. Contains conversation_id if redirect is needed,
+            otherwise an empty object.
+          content:
+            application/json:
+              schema:
+                type: object
+                properties:
+                  conversation_id:
+                    type: string
+                    description: The conversation ID to redirect to (only present when redirect is needed)
+        '500':
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+
+components:
+  securitySchemes:
+    bearerAuth:
+      type: http
+      scheme: bearer
+      description: |
+        Authentication via a Warp API key.
+
+  schemas:
+    RunAgentRequest:
+      type: object
+      description: |
+        Request body for creating a new agent run.
+        Either prompt or skill (via skill field or config.skill_spec) is required.
+      properties:
+        prompt:
+          type: string
+          description: |
+            The prompt/instruction for the agent to execute.
+            Required unless a skill is specified via the skill field or config.skill_spec.
+        skill:
+          type: string
+          description: |
+            Skill specification to use as the base prompt for the agent.
+            Supported formats:
+              - "repo:skill_name" - Simple name in specific repo
+              - "repo:skill_path" - Full path in specific repo
+              - "org/repo:skill_name" - Simple name with org and repo
+              - "org/repo:skill_path" - Full path with org and repo
+            When provided, this takes precedence over config.skill_spec.
+        config:
+          $ref: '#/components/schemas/AmbientAgentConfig'
+        title:
+          type: string
+          description: Custom title for the run (auto-generated if not provided)
+        team:
+          type: boolean
+          description: |
+            Whether to create a team-owned run.
+            Defaults to true for users on a single team.
+          x-go-type-skip-optional-pointer: false
+        agent_identity_uid:
+          type: string
+          description: |
+            Optional agent identity UID to use as the execution principal for the run.
+            This is only valid for runs that are team owned. 
+        conversation_id:
+          type: string
+          description: |
+            Optional conversation ID to continue an existing conversation.
+            If provided, the agent will continue from where the previous run left off.
+        attachments:
+          type: array
+          items:
+            $ref: '#/components/schemas/AttachmentInput'
+          description: |
+            Optional file attachments to include with the prompt (max 5).
+            Attachments are uploaded to cloud storage and made available to the agent.
+        parent_run_id:
+          type: string
+          description: |
+            Optional run ID of the parent that spawned this run.
+            Used for orchestration hierarchies.
+        interactive:
+          type: boolean
+          description: |
+            Whether the run should be interactive.
+            If not set, defaults to false.
+
+    RunAgentResponse:
+      type: object
+      required:
+        - run_id
+        - task_id
+        - state
+      properties:
+        run_id:
+          type: string
+          description: Unique identifier for the created run
+        task_id:
+          type: string
+          deprecated: true
+          x-stainless-deprecation-message: Use run_id instead.
+          description: Unique identifier for the task (same as run_id). Deprecated - use run_id instead.
+        state:
+          $ref: '#/components/schemas/RunState'
+        at_capacity:
+          type: boolean
+          description: Whether the system is at capacity when the run was created
+
+    ListRunsResponse:
+      type: object
+      required:
+        - runs
+        - page_info
+      properties:
+        runs:
+          type: array
+          items:
+            $ref: '#/components/schemas/RunItem'
+        page_info:
+          $ref: '#/components/schemas/PageInfo'
+
+    RunItem:
+      type: object
+      required:
+        - run_id
+        - task_id
+        - title
+        - state
+        - prompt
+        - created_at
+        - updated_at
+      properties:
+        run_id:
+          type: string
+          description: Unique identifier for the run
+        task_id:
+          type: string
+          deprecated: true
+          x-stainless-deprecation-message: Use run_id instead.
+          description: Unique identifier for the task (typically matches run_id). Deprecated - use run_id instead.
+        title:
+          type: string
+          description: Human-readable title for the run
+        state:
+          $ref: '#/components/schemas/RunState'
+        execution_location:
+          $ref: '#/components/schemas/RunExecutionLocation'
+        prompt:
+          type: string
+          description: The prompt/instruction for the agent
+        created_at:
+          type: string
+          format: date-time
+          description: Timestamp when the run was created (RFC3339)
+        updated_at:
+          type: string
+          format: date-time
+          description: Timestamp when the run was last updated (RFC3339)
+        started_at:
+          type: string
+          format: date-time
+          nullable: true
+          description: Timestamp when the agent started working on the run (RFC3339)
+        status_message:
+          $ref: '#/components/schemas/RunStatusMessage'
+        source:
+          $ref: '#/components/schemas/RunSourceType'
+        schedule:
+          $ref: '#/components/schemas/ScheduleInfo'
+        session_id:
+          type: string
+          description: UUID of the shared session (if available)
+        session_link:
+          type: string
+          format: uri
+          description: URL to view the agent session
+        trigger_url:
+          type: string
+          format: uri
+          description: URL to the run trigger (e.g. Slack thread, Linear issue, schedule)
+        creator:
+          $ref: '#/components/schemas/RunCreatorInfo'
+        request_usage:
+          $ref: '#/components/schemas/RequestUsage'
+        agent_config:
+          $ref: '#/components/schemas/AmbientAgentConfig'
+        conversation_id:
+          type: string
+          description: UUID of the conversation associated with the run
+        parent_run_id:
+          type: string
+          description: UUID of the parent run that spawned this run
+        is_sandbox_running:
+          type: boolean
+          description: Whether the sandbox environment is currently running
+        artifacts:
+          type: array
+          items:
+            $ref: '#/components/schemas/ArtifactItem'
+          description: Artifacts created during the run (plans, pull requests, etc.)
+        agent_skill:
+          $ref: '#/components/schemas/AgentSkill'
+        scope:
+          $ref: '#/components/schemas/Scope'
+
+    ConversationResponse:
+      type: object
+      required:
+        - conversation_id
+        - steps
+      properties:
+        conversation_id:
+          type: string
+          description: Unique identifier for the conversation
+        steps:
+          type: array
+          description: Root steps in the conversation
+          items:
+            $ref: '#/components/schemas/ConversationStep'
+
+    ConversationStep:
+      type: object
+      required:
+        - id
+        - messages
+        - steps
+      properties:
+        id:
+          type: string
+          description: Unique identifier for the step
+        description:
+          type: string
+          description: Original instruction or delegated work description for the step
+        summary:
+          type: string
+          description: Summary of the work completed for the step
+        started_at:
+          type: string
+          format: date-time
+          description: Earliest transcript message timestamp contained in this step or any nested step (RFC3339)
+        completed_at:
+          type: string
+          format: date-time
+          description: Latest transcript message timestamp contained in this step or any nested step (RFC3339)
+        messages:
+          type: array
+          description: Ordered normalized messages for this step
+          items:
+            $ref: '#/components/schemas/ConversationMessage'
+        steps:
+          type: array
+          description: Nested delegated work performed as part of this step
+          items:
+            $ref: '#/components/schemas/ConversationStep'
+
+    ConversationMessage:
+      type: object
+      required:
+        - role
+        - content
+      properties:
+        message_ids:
+          type: array
+          description: Underlying transcript message IDs grouped into this normalized message
+          items:
+            type: string
+        request_id:
+          type: string
+          description: Request identifier shared by transcript messages from the same request, when available
+        role:
+          $ref: '#/components/schemas/ConversationMessageRole'
+        timestamp:
+          type: string
+          format: date-time
+          description: Timestamp of the first transcript message included in this normalized message (RFC3339)
+        content:
+          type: array
+          items:
+            $ref: '#/components/schemas/ConversationContentBlock'
+
+    ConversationMessageRole:
+      type: string
+      description: Role of the normalized message
+      enum:
+        - user
+        - assistant
+        - tool
+        - system
+
+    ConversationContentBlock:
+      oneOf:
+        - $ref: '#/components/schemas/TextContentBlock'
+        - $ref: '#/components/schemas/ActionContentBlock'
+        - $ref: '#/components/schemas/ActionResultContentBlock'
+        - $ref: '#/components/schemas/EventContentBlock'
+      discriminator:
+        propertyName: type
+        mapping:
+          text: '#/components/schemas/TextContentBlock'
+          action: '#/components/schemas/ActionContentBlock'
+          action_result: '#/components/schemas/ActionResultContentBlock'
+          event: '#/components/schemas/EventContentBlock'
+
+    TextContentBlock:
+      type: object
+      required:
+        - type
+        - text
+      properties:
+        type:
+          type: string
+          enum:
+            - text
+        message_id:
+          type: string
+          description: Underlying transcript message ID that produced this content block, when available
+        text:
+          type: string
+          description: Plain text content
+
+    ActionCategory:
+      type: string
+      description: High-level category of an action performed during the conversation
+      enum:
+        - command
+        - files
+        - search
+        - integration
+        - documents
+        - computer
+        - review
+        - skill
+
+    ActionState:
+      type: string
+      description: State of an action result
+      enum:
+        - running
+        - completed
+        - failed
+        - denied
+
+    ActionContentBlock:
+      type: object
+      required:
+        - type
+        - id
+        - category
+        - name
+        - input
+      properties:
+        type:
+          type: string
+          enum:
+            - action
+        message_id:
+          type: string
+          description: Underlying transcript message ID that produced this content block, when available
+        id:
+          type: string
+          description: Unique identifier for the action
+        category:
+          $ref: '#/components/schemas/ActionCategory'
+        name:
+          type: string
+          description: Public action name, such as run_command or edit_files
+        input:
+          type: object
+          additionalProperties: true
+          description: Curated public input for this action. This object is owned by the API and is not a raw internal tool payload.
+
+    ActionResultContentBlock:
+      type: object
+      required:
+        - type
+        - action_id
+        - category
+        - name
+        - state
+        - output
+      properties:
+        type:
+          type: string
+          enum:
+            - action_result
+        message_id:
+          type: string
+          description: Underlying transcript message ID that produced this content block, when available
+        action_id:
+          type: string
+          description: Identifier of the corresponding action
+        category:
+          $ref: '#/components/schemas/ActionCategory'
+        name:
+          type: string
+          description: Public action name matching the corresponding action block
+        state:
+          $ref: '#/components/schemas/ActionState'
+        output:
+          type: object
+          additionalProperties: true
+          description: Curated public result for this action. Large or binary internal payloads should be summarized rather than passed through raw.
+
+    EventContentBlock:
+      type: object
+      required:
+        - type
+        - name
+        - data
+      properties:
+        type:
+          type: string
+          enum:
+            - event
+        message_id:
+          type: string
+          description: Underlying transcript message ID that produced this content block, when available
+        name:
+          type: string
+          description: Event type for intentionally exposed non-core transcript events
+        data:
+          type: object
+          additionalProperties: true
+          description: Minimal structured metadata for the event
+
+    ArtifactItem:
+      oneOf:
+        - $ref: '#/components/schemas/PlanArtifact'
+        - $ref: '#/components/schemas/PullRequestArtifact'
+        - $ref: '#/components/schemas/ScreenshotArtifact'
+        - $ref: '#/components/schemas/FileArtifact'
+      discriminator:
+        propertyName: artifact_type
+        mapping:
+          PLAN: '#/components/schemas/PlanArtifact'
+          PULL_REQUEST: '#/components/schemas/PullRequestArtifact'
+          SCREENSHOT: '#/components/schemas/ScreenshotArtifact'
+          FILE: '#/components/schemas/FileArtifact'
+
+    PlanArtifact:
+      type: object
+      required:
+        - artifact_type
+        - created_at
+        - data
+      properties:
+        artifact_type:
+          type: string
+          enum:
+            - PLAN
+          description: Type of the artifact
+        created_at:
+          type: string
+          format: date-time
+          description: Timestamp when the artifact was created (RFC3339)
+        data:
+          $ref: '#/components/schemas/PlanArtifactData'
+
+    PullRequestArtifact:
+      type: object
+      required:
+        - artifact_type
+        - created_at
+        - data
+      properties:
+        artifact_type:
+          type: string
+          enum:
+            - PULL_REQUEST
+          description: Type of the artifact
+        created_at:
+          type: string
+          format: date-time
+          description: Timestamp when the artifact was created (RFC3339)
+        data:
+          $ref: '#/components/schemas/PullRequestArtifactData'
+
+    ScreenshotArtifact:
+      type: object
+      required:
+        - artifact_type
+        - created_at
+        - data
+      properties:
+        artifact_type:
+          type: string
+          enum:
+            - SCREENSHOT
+          description: Type of the artifact
+        created_at:
+          type: string
+          format: date-time
+          description: Timestamp when the artifact was created (RFC3339)
+        data:
+          $ref: '#/components/schemas/ScreenshotArtifactData'
+
+    FileArtifact:
+      type: object
+      required:
+        - artifact_type
+        - created_at
+        - data
+      properties:
+        artifact_type:
+          type: string
+          enum:
+            - FILE
+          description: Type of the artifact
+        created_at:
+          type: string
+          format: date-time
+          description: Timestamp when the artifact was created (RFC3339)
+        data:
+          $ref: '#/components/schemas/FileArtifactData'
+
+    PlanArtifactData:
+      type: object
+      required:
+        - document_uid
+      properties:
+        artifact_uid:
+          type: string
+          description: Unique identifier for the plan artifact, usable with the artifact retrieval endpoint
+        document_uid:
+          type: string
+          description: Unique identifier for the plan document
+        notebook_uid:
+          type: string
+          description: Unique identifier for the associated notebook
+        url:
+          type: string
+          format: uri
+          description: URL to open the plan in Warp Drive
+        title:
+          type: string
+          description: Title of the plan
+
+    PullRequestArtifactData:
+      type: object
+      required:
+        - url
+        - branch
+      properties:
+        url:
+          type: string
+          format: uri
+          description: URL of the pull request
+        branch:
+          type: string
+          description: Branch name for the pull request
+
+    ScreenshotArtifactData:
+      type: object
+      required:
+        - artifact_uid
+        - mime_type
+      properties:
+        artifact_uid:
+          type: string
+          description: Unique identifier for the screenshot artifact
+        mime_type:
+          type: string
+          description: MIME type of the screenshot image
+        description:
+          type: string
+          description: Optional description of the screenshot
+
+    FileArtifactData:
+      type: object
+      required:
+        - artifact_uid
+        - filepath
+        - filename
+        - mime_type
+      properties:
+        artifact_uid:
+          type: string
+          description: Unique identifier for the file artifact
+        filepath:
+          type: string
+          description: Conversation-relative filepath for the uploaded file
+        filename:
+          type: string
+          description: Last path component of filepath
+        description:
+          type: string
+          description: Optional description of the file
+        mime_type:
+          type: string
+          description: MIME type of the uploaded file
+        size_bytes:
+          type: integer
+          format: int64
+          description: Size of the uploaded file in bytes
+          x-go-type-skip-optional-pointer: false
+
+    ScheduleInfo:
+      type: object
+      description: Information about the schedule that triggered this run (only present for scheduled runs)
+      required:
+        - schedule_id
+        - schedule_name
+        - cron_schedule
+      properties:
+        schedule_id:
+          type: string
+          description: Unique identifier for the schedule
+        schedule_name:
+          type: string
+          description: Name of the schedule at the time the run was created
+        cron_schedule:
+          type: string
+          description: Cron expression at the time the run was created
+
+    PageInfo:
+      type: object
+      required:
+        - has_next_page
+      properties:
+        has_next_page:
+          type: boolean
+          description: Whether there are more results available
+        next_cursor:
+          type: string
+          description: Opaque cursor for fetching the next page
+
+    RunStatusMessage:
+      type: object
+      description: |
+        Status message for a run. For terminal error states, includes structured
+        error code and retryability info from the platform error catalog.
+      required:
+        - message
+      properties:
+        message:
+          type: string
+          description: Human-readable status message
+        error_code:
+          $ref: '#/components/schemas/PlatformErrorCode'
+        retryable:
+          type: boolean
+          description: |
+            Whether the error is transient and the client may retry by submitting
+            a new run. Only present on terminal error states. When false, retrying
+            without addressing the underlying cause will not succeed.
+
+    RequestUsage:
+      type: object
+      description: Resource usage information for the run
+      properties:
+        inference_cost:
+          type: number
+          format: double
+          description: Cost of LLM inference for the run
+        compute_cost:
+          type: number
+          format: double
+          description: Cost of compute resources for the run
+
+    RunCreatorInfo:
+      type: object
+      properties:
+        type:
+          type: string
+          enum:
+            - user
+            - service_account
+          description: Type of the creator principal
+        uid:
+          type: string
+          description: Unique identifier of the creator
+        display_name:
+          type: string
+          description: Display name of the creator
+        email:
+          type: string
+          description: Email address of the creator
+        photo_url:
+          type: string
+          format: uri
+          description: URL to the creator's photo
+
+    RunState:
+      type: string
+      enum:
+        - QUEUED
+        - PENDING
+        - CLAIMED
+        - INPROGRESS
+        - SUCCEEDED
+        - FAILED
+        - BLOCKED
+        - ERROR
+        - CANCELLED
+      description: |
+        Current state of the run:
+        - QUEUED: Run is waiting to be picked up
+        - PENDING: Run is being prepared
+        - CLAIMED: Run has been claimed by a worker
+        - INPROGRESS: Run is actively being executed
+        - SUCCEEDED: Run completed successfully
+        - FAILED: Run failed
+        - BLOCKED: Run is blocked (e.g., awaiting user input or approval)
+        - ERROR: Run encountered an error
+        - CANCELLED: Run was cancelled by user
+    RunSourceType:
+      type: string
+      enum:
+        - LINEAR
+        - API
+        - SLACK
+        - LOCAL
+        - SCHEDULED_AGENT
+        - WEB_APP
+        - GITHUB_ACTION
+        - CLOUD_MODE
+        - CLI
+      description: |
+        Source that created the run:
+        - LINEAR: Created from Linear integration
+        - API: Created via the Warp API
+        - SLACK: Created from Slack integration
+        - LOCAL: Created from local CLI/app
+        - SCHEDULED_AGENT: Created by a scheduled agent
+        - WEB_APP: Created from the Warp web app
+        - GITHUB_ACTION: Created from a GitHub action
+        - CLOUD_MODE: Created from a Cloud Mode
+        - CLI: Created from the CLI
+    RunExecutionLocation:
+      type: string
+      enum:
+        - LOCAL
+        - REMOTE
+      description: |
+        Where the run executed:
+        - LOCAL: Executed in the user's local Oz environment
+        - REMOTE: Executed by a remote/cloud worker
+    # TODO: Rename AmbientAgentConfig to AgentConfig in a future API version.
+    # The "Ambient" prefix is an internal legacy name and should not be user-facing.
+    AmbientAgentConfig:
+      type: object
+      description: Configuration for a cloud agent run
+      properties:
+        name:
+          type: string
+          description: |
+            Human-readable label for grouping, filtering, and traceability.
+            Automatically set to the skill name when running a skill-based agent.
+            Set this explicitly to categorize runs by intent (e.g., "nightly-dependency-check")
+            so you can filter and track them via the name query parameter on GET /agent/runs.
+        model_id:
+          type: string
+          description: LLM model to use (uses team default if not specified)
+          x-stainless-naming:
+            python:
+              method_argument: "llm_id"
+        base_prompt:
+          type: string
+          description: Custom base prompt for the agent
+        environment_id:
+          type: string
+          description: UID of the environment to run the agent in
+        skill_spec:
+          type: string
+          description: |
+            Skill specification identifying which agent skill to use.
+            Format: "{owner}/{repo}:{skill_path}"
+            Example: "warpdotdev/warp-server:.claude/skills/deploy/SKILL.md"
+            Use the list agents endpoint to discover available skills.
+        mcp_servers:
+          type: object
+          additionalProperties:
+            $ref: '#/components/schemas/MCPServerConfig'
+          description: Map of MCP server configurations by name
+        computer_use_enabled:
+          type: boolean
+          description: |
+            Controls whether computer use is enabled for this agent.
+            If not set, defaults to false.
+          x-go-type-skip-optional-pointer: false
+        idle_timeout_minutes:
+          type: integer
+          format: int32
+          minimum: 1
+          maximum: 60
+          description: |
+            Number of minutes to keep the agent environment alive after task completion.
+            If not set, defaults to 10 minutes.
+            Maximum allowed value is min(60, floor(max_instance_runtime_seconds / 60) for your billing tier).
+          x-go-type-skip-optional-pointer: false
+        worker_host:
+          type: string
+          description: |
+            Self-hosted worker ID that should execute this task.
+            If not specified or set to "warp", the task runs on Warp-hosted workers.
+        harness:
+          $ref: '#/components/schemas/Harness'
+        harness_auth_secrets:
+          $ref: '#/components/schemas/HarnessAuthSecrets'
+
+    Harness:
+      type: object
+      description: |
+        Specifies which execution harness to use for the agent run.
+        Default (nil/empty) uses Warp's built-in harness.
+      properties:
+        type:
+          type: string
+          enum:
+            - oz
+            - claude
+          description: |
+            The harness type identifier.
+            - oz: Warp's built-in harness (default)
+            - claude: Claude Code harness
+
+    HarnessAuthSecrets:
+      type: object
+      description: |
+        Authentication secrets for third-party harnesses.
+        Only the secret for the harness specified gets injected into the environment.
+      properties:
+        claude_auth_secret_name:
+          type: string
+          description: |
+            Name of a managed secret for Claude Code harness authentication.
+            The secret must exist within the caller's personal or team scope.
+            Only applicable when harness type is "claude".
+
+    MCPServerConfig:
+      type: object
+      description: |
+        Configuration for an MCP server. Must have exactly one of: warp_id, command, or url.
+      properties:
+        warp_id:
+          type: string
+          description: Reference to a Warp shared MCP server by UUID
+        command:
+          type: string
+          description: Stdio transport - command to run
+        args:
+          type: array
+          items:
+            type: string
+          description: Stdio transport - command arguments
+        url:
+          type: string
+          format: uri
+          description: SSE/HTTP transport - server URL
+        env:
+          type: object
+          additionalProperties:
+            type: string
+          description: Environment variables for the server
+        headers:
+          type: object
+          additionalProperties:
+            type: string
+          description: HTTP headers for SSE/HTTP transport
+
+    Error:
+      type: object
+      description: |
+        Error response following RFC 7807 (Problem Details for HTTP APIs).
+        Includes backward-compatible extension members.
+
+        The response uses the `application/problem+json` content type.
+        Additional extension members (e.g., `auth_url`, `provider`) may be
+        present depending on the error code.
+      required:
+        - type
+        - title
+        - status
+        - error
+      properties:
+        type:
+          type: string
+          format: uri
+          description: |
+            A URI reference that identifies the problem type (RFC 7807).
+            Format: `https://docs.warp.dev/reference/api-and-sdk/troubleshooting/errors/{error_code}`
+            See PlatformErrorCode for the list of possible error codes.
+        title:
+          type: string
+          description: A short, human-readable summary of the problem type (RFC 7807)
+        status:
+          type: integer
+          description: The HTTP status code for this occurrence of the problem (RFC 7807)
+        detail:
+          type: string
+          description: A human-readable explanation specific to this occurrence of the problem (RFC 7807)
+        instance:
+          type: string
+          description: The request path that generated this error (RFC 7807)
+        error:
+          type: string
+          description: |
+            Human-readable error message combining title and detail.
+            Backward-compatible extension member for older clients.
+        retryable:
+          type: boolean
+          description: |
+            Whether the request can be retried. When true, the error is transient
+            and the request may be retried. When false, retrying without addressing
+            the underlying cause will not succeed.
+        trace_id:
+          type: string
+          description: OpenTelemetry trace ID for debugging and support requests
+
+    ArtifactResponse:
+      oneOf:
+        - $ref: '#/components/schemas/PlanArtifactResponse'
+        - $ref: '#/components/schemas/ScreenshotArtifactResponse'
+        - $ref: '#/components/schemas/FileArtifactResponse'
+      discriminator:
+        propertyName: artifact_type
+        mapping:
+          PLAN: '#/components/schemas/PlanArtifactResponse'
+          SCREENSHOT: '#/components/schemas/ScreenshotArtifactResponse'
+          FILE: '#/components/schemas/FileArtifactResponse'
+    PlanArtifactResponse:
+      type: object
+      description: Response for retrieving a plan artifact.
+      required:
+        - artifact_uid
+        - artifact_type
+        - created_at
+        - data
+      properties:
+        artifact_uid:
+          type: string
+          description: Unique identifier (UUID) for the artifact
+        artifact_type:
+          type: string
+          enum:
+            - PLAN
+          description: Type of the artifact
+        created_at:
+          type: string
+          format: date-time
+          description: Timestamp when the artifact was created (RFC3339)
+        data:
+          $ref: '#/components/schemas/PlanArtifactResponseData'
+
+    PlanArtifactResponseData:
+      type: object
+      description: Response data for a plan artifact, including current markdown content.
+      required:
+        - document_uid
+        - notebook_uid
+        - content
+        - content_type
+      properties:
+        document_uid:
+          type: string
+          description: Unique identifier for the plan document
+        notebook_uid:
+          type: string
+          description: Unique identifier for the associated notebook
+        url:
+          type: string
+          format: uri
+          description: URL to open the plan in Warp Drive
+        title:
+          type: string
+          description: Current title of the plan
+        content:
+          type: string
+          description: Current markdown content of the plan
+        content_type:
+          type: string
+          description: MIME type of the returned plan content
+
+    ScreenshotArtifactResponse:
+      type: object
+      description: Response for retrieving a screenshot artifact.
+      required:
+        - artifact_uid
+        - artifact_type
+        - created_at
+        - data
+      properties:
+        artifact_uid:
+          type: string
+          description: Unique identifier (UUID) for the artifact
+        artifact_type:
+          type: string
+          enum:
+            - SCREENSHOT
+          description: Type of the artifact
+        created_at:
+          type: string
+          format: date-time
+          description: Timestamp when the artifact was created (RFC3339)
+        data:
+          $ref: '#/components/schemas/ScreenshotArtifactResponseData'
+
+    ScreenshotArtifactResponseData:
+      type: object
+      description: Response data for a screenshot artifact, including a signed download URL.
+      required:
+        - download_url
+        - expires_at
+        - content_type
+      properties:
+        download_url:
+          type: string
+          format: uri
+          description: Time-limited signed URL to download the screenshot
+        expires_at:
+          type: string
+          format: date-time
+          description: Timestamp when the download URL expires (RFC3339)
+        content_type:
+          type: string
+          description: MIME type of the screenshot (e.g., image/png)
+        description:
+          type: string
+          description: Optional description of the screenshot
+
+    FileArtifactResponse:
+      type: object
+      description: Response for retrieving a file artifact.
+      required:
+        - artifact_uid
+        - artifact_type
+        - created_at
+        - data
+      properties:
+        artifact_uid:
+          type: string
+          description: Unique identifier (UUID) for the artifact
+        artifact_type:
+          type: string
+          enum:
+            - FILE
+          description: Type of the artifact
+        created_at:
+          type: string
+          format: date-time
+          description: Timestamp when the artifact was created (RFC3339)
+        data:
+          $ref: '#/components/schemas/FileArtifactResponseData'
+
+    FileArtifactResponseData:
+      type: object
+      description: Response data for a file artifact, including a signed download URL.
+      required:
+        - download_url
+        - expires_at
+        - content_type
+        - filepath
+        - filename
+      properties:
+        download_url:
+          type: string
+          format: uri
+          description: Time-limited signed URL to download the file
+        expires_at:
+          type: string
+          format: date-time
+          description: Timestamp when the download URL expires (RFC3339)
+        content_type:
+          type: string
+          description: MIME type of the uploaded file
+        filepath:
+          type: string
+          description: Conversation-relative filepath for the uploaded file
+        filename:
+          type: string
+          description: Last path component of filepath
+        description:
+          type: string
+          description: Optional description of the file
+        size_bytes:
+          type: integer
+          format: int64
+          description: Size of the uploaded file in bytes
+          x-go-type-skip-optional-pointer: false
+
+    AttachmentInput:
+      type: object
+      description: A base64-encoded file attachment to include with the prompt
+      required:
+        - file_name
+        - mime_type
+        - data
+      properties:
+        file_name:
+          type: string
+          description: Name of the attached file
+        mime_type:
+          type: string
+          description: |
+            MIME type of the attachment.
+            Supported image types: image/jpeg, image/png, image/gif, image/webp
+        data:
+          type: string
+          format: byte
+          description: Base64-encoded attachment data
+
+    ScheduledAgentItem:
+      type: object
+      required:
+        - id
+        - name
+        - cron_schedule
+        - enabled
+        - prompt
+        - created_at
+        - updated_at
+      properties:
+        id:
+          type: string
+          description: Unique identifier for the scheduled agent
+        name:
+          type: string
+          description: Human-readable name for the schedule
+        cron_schedule:
+          type: string
+          description: Cron expression defining when the agent runs (e.g., "0 9 * * *" for daily at 9am UTC)
+        enabled:
+          type: boolean
+          description: Whether the schedule is currently active
+        prompt:
+          type: string
+          description: The prompt/instruction for the agent to execute
+        last_spawn_error:
+          type: string
+          nullable: true
+          description: Error message from the last failed spawn attempt, if any
+        agent_config:
+          $ref: '#/components/schemas/AmbientAgentConfig'
+        environment:
+          allOf:
+            - $ref: '#/components/schemas/CloudEnvironmentConfig'
+          description: Resolved environment configuration (if agent_config references an environment_id)
+        created_at:
+          type: string
+          format: date-time
+          description: Timestamp when the schedule was created (RFC3339)
+        updated_at:
+          type: string
+          format: date-time
+          description: Timestamp when the schedule was last updated (RFC3339)
+        created_by:
+          $ref: '#/components/schemas/RunCreatorInfo'
+        updated_by:
+          $ref: '#/components/schemas/RunCreatorInfo'
+        history:
+          $ref: '#/components/schemas/ScheduledAgentHistoryItem'
+        scope:
+          $ref: '#/components/schemas/Scope'
+
+    ScheduledAgentHistoryItem:
+      type: object
+      description: Scheduler-derived history metadata for a scheduled agent
+      properties:
+        last_ran:
+          type: string
+          format: date-time
+          nullable: true
+          description: Timestamp of the last successful run (RFC3339)
+        next_run:
+          type: string
+          format: date-time
+          nullable: true
+          description: Timestamp of the next scheduled run (RFC3339)
+
+    CreateScheduledAgentRequest:
+      type: object
+      description: |
+        Request body for creating a new scheduled agent.
+        Either prompt or agent_config.skill_spec is required.
+      required:
+        - name
+        - cron_schedule
+      properties:
+        name:
+          type: string
+          description: Human-readable name for the schedule
+        cron_schedule:
+          type: string
+          description: Cron expression defining when the agent runs (e.g., "0 9 * * *" for daily at 9am UTC)
+        prompt:
+          type: string
+          description: |
+            The prompt/instruction for the agent to execute.
+            Required unless agent_config.skill_spec is provided.
+        enabled:
+          type: boolean
+          description: Whether the schedule should be active immediately
+          default: true
+        agent_config:
+          $ref: '#/components/schemas/AmbientAgentConfig'
+        team:
+          type: boolean
+          description: |
+            Whether to create a team-owned schedule.
+            Defaults to true for users on a single team.
+          x-go-type-skip-optional-pointer: false
+
+    UpdateScheduledAgentRequest:
+      type: object
+      description: |
+        Request body for updating a scheduled agent.
+        Either prompt or agent_config.skill_spec is required.
+      required:
+        - name
+        - cron_schedule
+        - enabled
+      properties:
+        name:
+          type: string
+          description: Human-readable name for the schedule
+        cron_schedule:
+          type: string
+          description: Cron expression defining when the agent runs
+        prompt:
+          type: string
+          description: |
+            The prompt/instruction for the agent to execute.
+            Required unless agent_config.skill_spec is provided.
+        enabled:
+          type: boolean
+          description: Whether the schedule should be active
+        agent_config:
+          $ref: '#/components/schemas/AmbientAgentConfig'
+
+    ListScheduledAgentsResponse:
+      type: object
+      required:
+        - schedules
+      properties:
+        schedules:
+          type: array
+          items:
+            $ref: '#/components/schemas/ScheduledAgentItem'
+          description: List of scheduled agents
+
+    DeleteScheduledAgentResponse:
+      type: object
+      required:
+        - success
+      properties:
+        success:
+          type: boolean
+          description: Whether the deletion was successful
+
+    CloudEnvironmentConfig:
+      type: object
+      description: Configuration for a cloud environment used by scheduled agents
+      properties:
+        name:
+          type: string
+          description: Human-readable name for the environment
+        description:
+          type: string
+          nullable: true
+          description: Optional description of the environment
+        docker_image:
+          type: string
+          description: Docker image to use (e.g., "ubuntu:latest" or "registry/repo:tag")
+        github_repos:
+          type: array
+          items:
+            $ref: '#/components/schemas/GitHubRepo'
+          description: List of GitHub repositories to clone into the environment
+        setup_commands:
+          type: array
+          items:
+            type: string
+          description: Shell commands to run during environment setup
+        providers:
+          $ref: '#/components/schemas/ProvidersConfig'
+
+    ProvidersConfig:
+      type: object
+      description: Optional cloud provider configurations for automatic auth
+      properties:
+        gcp:
+          $ref: '#/components/schemas/GcpProviderConfig'
+        aws:
+          $ref: '#/components/schemas/AwsProviderConfig'
+
+    GcpProviderConfig:
+      type: object
+      description: GCP Workload Identity Federation settings
+      required:
+        - project_number
+        - workload_identity_federation_pool_id
+        - workload_identity_federation_provider_id
+      externalDocs:
+        description: Google documentation on Workload Identity Federation
+        url: https://docs.cloud.google.com/iam/docs/workload-identity-federation
+      properties:
+        project_number:
+          type: string
+          description: GCP project number
+        workload_identity_federation_pool_id:
+          type: string
+          description: Workload Identity Federation pool ID
+        workload_identity_federation_provider_id:
+          type: string
+          description: Workload Identity Federation provider ID
+
+    AwsProviderConfig:
+      type: object
+      description: AWS IAM role assumption settings
+      required:
+        - role_arn
+      externalDocs:
+        description: AWS documentation on IAM OIDC federation
+        url: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_oidc.html
+      properties:
+        role_arn:
+          type: string
+          description: AWS IAM role ARN to assume
+
+    GitHubRepo:
+      type: object
+      required:
+        - owner
+        - repo
+      properties:
+        owner:
+          type: string
+          description: GitHub repository owner (user or organization)
+        repo:
+          type: string
+          description: GitHub repository name
+
+    ListAgentsResponse:
+      type: object
+      required:
+        - agents
+      properties:
+        agents:
+          type: array
+          items:
+            $ref: '#/components/schemas/AgentListItem'
+          description: List of available agents
+
+    AgentListItem:
+      type: object
+      required:
+        - name
+        - variants
+      properties:
+        name:
+          type: string
+          description: Human-readable name of the agent
+        variants:
+          type: array
+          items:
+            $ref: '#/components/schemas/AgentListVariant'
+          description: Available variants of this agent
+
+    AgentListVariant:
+      type: object
+      required:
+        - id
+        - description
+        - base_prompt
+        - source
+        - environments
+      properties:
+        id:
+          type: string
+          description: |
+            Stable identifier for this skill variant.
+            Format: "{owner}/{repo}:{skill_path}"
+            Example: "warpdotdev/warp-server:.claude/skills/deploy/SKILL.md"
+        description:
+          type: string
+          description: Description of the agent variant
+        base_prompt:
+          type: string
+          description: Base prompt/instructions for the agent
+        source:
+          $ref: '#/components/schemas/AgentListSource'
+        environments:
+          type: array
+          items:
+            $ref: '#/components/schemas/AgentListEnvironment'
+          description: Environments where this agent variant is available
+        last_run_timestamp:
+          type: string
+          format: date-time
+          nullable: true
+          description: Timestamp of the last time this skill was run (RFC3339)
+        error:
+          type: string
+          description: |
+            Non-empty when the skill's SKILL.md file exists but is malformed.
+            Contains a description of the parse failure. Only present when
+            include_malformed_skills=true is passed to the list agents endpoint.
+
+    AgentListSource:
+      type: object
+      required:
+        - owner
+        - name
+        - skill_path
+      properties:
+        owner:
+          type: string
+          description: GitHub repository owner
+        name:
+          type: string
+          description: GitHub repository name
+        skill_path:
+          type: string
+          description: Path to the skill definition file within the repository
+        worker_host:
+          type: string
+          description: |
+            Self-hosted worker host that reported this skill.
+            Present only for skills discovered from self-hosted workers
+            (as opposed to skills from GitHub repos linked to environments).
+
+    AgentListEnvironment:
+      type: object
+      required:
+        - uid
+        - name
+      properties:
+        uid:
+          type: string
+          description: Unique identifier for the environment
+        name:
+          type: string
+          description: Human-readable name of the environment
+
+    Scope:
+      type: object
+      description: Ownership scope for a resource (team or personal)
+      required:
+        - type
+      properties:
+        type:
+          type: string
+          enum:
+            - User
+            - Team
+          description: Type of ownership ("User" for personal, "Team" for team-owned)
+        uid:
+          type: string
+          description: UID of the owning user or team
+
+    PlatformErrorCode:
+      type: string
+      description: |
+        Machine-readable error code identifying the problem type.
+        Used in the `type` URI of Error responses and in the `error_code`
+        field of RunStatusMessage.
+
+        User errors (run transitions to FAILED):
+        - `insufficient_credits` — Team has no remaining add-on credits
+        - `feature_not_available` — Required feature not enabled for user's plan
+        - `external_authentication_required` — User hasn't authorized a required external service
+        - `not_authorized` — Principal lacks permission for the requested operation
+        - `invalid_request` — Request is malformed or contains invalid parameters
+        - `resource_not_found` — Referenced resource does not exist
+        - `budget_exceeded` — Spending budget limit has been reached
+        - `integration_disabled` — Integration is disabled and must be enabled
+        - `integration_not_configured` — Integration setup is incomplete
+        - `operation_not_supported` — Requested operation not supported for this resource/state
+        - `environment_setup_failed` — Client-side environment setup failed
+        - `content_policy_violation` — Prompt or setup commands violated content policy
+        - `conflict` — Request conflicts with the current state of the resource
+
+        Warp errors (run transitions to ERROR):
+        - `authentication_required` — Request lacks valid authentication credentials
+        - `resource_unavailable` — Transient infrastructure issue (retryable)
+        - `internal_error` — Unexpected server-side error (retryable)
+      enum:
+        - insufficient_credits
+        - feature_not_available
+        - external_authentication_required
+        - not_authorized
+        - invalid_request
+        - resource_not_found
+        - budget_exceeded
+        - integration_disabled
+        - integration_not_configured
+        - operation_not_supported
+        - environment_setup_failed
+        - content_policy_violation
+        - conflict
+        - authentication_required
+        - resource_unavailable
+        - internal_error
+
+    CreateExternalConversationRequest:
+      type: object
+      description: Request body for creating a new external conversation for a third-party harness.
+      required:
+        - format
+      properties:
+        format:
+          type: string
+          x-oapi-codegen-extra-tags:
+            binding: required
+          description: |
+            The conversation format identifying the harness type.
+
+    CreateExternalConversationResponse:
+      type: object
+      required:
+        - conversation_id
+      properties:
+        conversation_id:
+          type: string
+          description: The unique identifier of the newly created conversation.
+
+    ResolvePromptRequest:
+      type: object
+      description: Request body for resolving the effective prompt for a task.
+      properties:
+        skill:
+          type: object
+          description: Optional skill metadata to prepend to the prompt.
+          required:
+            - name
+            - content
+          properties:
+            name:
+              type: string
+              description: Human-readable name of the skill
+            content:
+              type: string
+              description: The resolved skill content
+            path:
+              type: string
+              description: Full path to SKILL.md (optional)
+        attachments_dir:
+          type: string
+          description: Directory where attachments were downloaded locally
+
+    ResolvePromptResponse:
+      type: object
+      required:
+        - prompt
+      properties:
+        prompt:
+          type: string
+          description: The resolved prompt
+        system_prompt:
+          type: string
+          description: Optional system prompt addition for the harness
+
+    GetUploadTargetRequest:
+      type: object
+      description: Request body for obtaining a conversation-scoped upload target.
+      required:
+        - conversation_id
+      properties:
+        conversation_id:
+          type: string
+          x-oapi-codegen-extra-tags:
+            binding: required
+          description: The conversation ID to associate the uploaded data with.
+
+    UploadTarget:
+      type: object
+      description: |
+        A description of where and how to upload a blob.
+        Use the `method` and `url` to upload, including all `headers` in the request.
+        Pass the blob to upload as the request body.
+      required:
+        - url
+        - method
+        - headers
+      properties:
+        url:
+          type: string
+          format: uri
+          description: The presigned URL to upload the blob to.
+        method:
+          type: string
+          enum:
+            - PUT
+            - POST
+          description: The HTTP method to use for the upload.
+        headers:
+          type: object
+          additionalProperties:
+            type: string
+          description: HTTP headers that must be included in the upload request.
+
+    ListModelsResponse:
+      type: object
+      required:
+        - default_model_id
+        - models
+      properties:
+        default_model_id:
+          type: string
+          description: The ID of the default model for agent runs
+        models:
+          type: array
+          items:
+            $ref: '#/components/schemas/ModelInfo'
+          description: List of available models
+
+    ModelInfo:
+      type: object
+      required:
+        - id
+        - display_name
+        - provider
+        - vision_supported
+      properties:
+        id:
+          type: string
+          description: Unique identifier for the model (e.g. "claude-4-6-opus-high" or "gpt-5-4-high")
+        display_name:
+          type: string
+          description: Human-readable name of the model
+        provider:
+          type: string
+          enum:
+            - OPENAI
+            - ANTHROPIC
+            - GOOGLE
+            - UNKNOWN
+          description: The LLM provider
+        vision_supported:
+          type: boolean
+          description: Whether the model supports vision/image inputs
+        description:
+          type: string
+          description: Optional extra descriptor for the model
+        reasoning_level:
+          type: string
+          description: Reasoning level descriptor, if any (e.g. "low", "medium", "high")
+        disable_reason:
+          type: string
+          enum:
+            - PROVIDER_OUTAGE
+            - OUT_OF_REQUESTS
+            - ADMIN_DISABLED
+            - REQUIRES_UPGRADE
+          description: If set, the model is currently unavailable for the given reason
+
+    NotifyUserRequest:
+      type: object
+      description: Request body for sending a progress notification to the task's originating platform.
+      required:
+        - message
+      properties:
+        message:
+          type: string
+          x-oapi-codegen-extra-tags:
+            binding: required
+          description: |
+            The progress update message to send. Supports Markdown formatting.
+
+    FinishTaskRequest:
+      type: object
+      description: |
+        Request body for reporting task completion or failure.
+        Pull request links and branches are derived automatically from artifacts
+        previously reported via the report artifact endpoint.
+      required:
+        - success
+        - summary
+      properties:
+        success:
+          type: boolean
+          description: Whether the task completed successfully.
+        summary:
+          type: string
+          x-oapi-codegen-extra-tags:
+            binding: required
+          description: |
+            A summary of what was accomplished. If there are artifacts like
+            pull requests, describe what was created.
+
+    ReportArtifactRequest:
+      oneOf:
+        - $ref: '#/components/schemas/ReportPullRequestArtifactRequest'
+      discriminator:
+        propertyName: artifact_type
+        mapping:
+          PULL_REQUEST: '#/components/schemas/ReportPullRequestArtifactRequest'
+
+    ReportPullRequestArtifactRequest:
+      type: object
+      description: Request body for reporting a pull request artifact.
+      required:
+        - artifact_type
+        - data
+      properties:
+        artifact_type:
+          type: string
+          enum:
+            - PULL_REQUEST
+          description: Type of artifact being reported.
+        data:
+          $ref: '#/components/schemas/PullRequestArtifactData'
+
+    ReportArtifactResponse:
+      type: object
+      required:
+        - artifact_uid
+      properties:
+        artifact_uid:
+          type: string
+          description: Unique identifier for the created artifact
+
+    AgentSkill:
+      type: object
+      description: |
+        Information about the agent skill used for the run.
+        Either full_path or bundled_skill_id will be set, but not both.
+      properties:
+        name:
+          type: string
+          description: Human-readable name of the skill
+        description:
+          type: string
+          description: Description of the skill
+        full_path:
+          type: string
+          description: Path to the SKILL.md file (for file-based skills)
+        bundled_skill_id:
+          type: string
+          description: Unique identifier for bundled skills
+
+    ListEnvironmentsResponse:
+      type: object
+      required:
+        - environments
+      properties:
+        environments:
+          type: array
+          items:
+            $ref: '#/components/schemas/CloudEnvironment'
+          description: List of accessible cloud environments
+
+    CloudEnvironment:
+      type: object
+      description: A cloud environment for running agents
+      required:
+        - uid
+        - config
+        - last_updated
+        - setup_failed
+      properties:
+        uid:
+          type: string
+          description: Unique identifier for the environment
+        config:
+          $ref: '#/components/schemas/CloudEnvironmentConfig'
+        last_updated:
+          type: string
+          format: date-time
+          description: Timestamp when the environment was last updated (RFC3339)
+        last_task_run_timestamp:
+          type: string
+          format: date-time
+          nullable: true
+          description: Timestamp of the most recent task run in this environment (RFC3339)
+        last_task_created:
+          $ref: '#/components/schemas/EnvironmentLastTask'
+        setup_failed:
+          type: boolean
+          description: True when the most recent task failed during setup before it started running
+        scope:
+          $ref: '#/components/schemas/Scope'
+        creator:
+          $ref: '#/components/schemas/RunCreatorInfo'
+        last_editor:
+          $ref: '#/components/schemas/RunCreatorInfo'
+
+    CreateAgentRequest:
+      type: object
+      required:
+        - name
+      properties:
+        name:
+          type: string
+          description: A name for the agent
+
+    UpdateAgentRequest:
+      type: object
+      properties:
+        name:
+          type: string
+          description: The new name for the agent
+
+    AgentResponse:
+      type: object
+      required:
+        - uid
+        - name
+        - available
+        - created_at
+      properties:
+        uid:
+          type: string
+          description: Unique identifier for the agent
+        name:
+          type: string
+          description: Name of the agent
+        available:
+          type: boolean
+          description: Whether this agent is within the team's plan limit and can be used for runs
+        created_at:
+          type: string
+          format: date-time
+          description: When the agent was created (RFC3339)
+
+    ListAgentIdentitiesResponse:
+      type: object
+      required:
+        - agents
+      properties:
+        agents:
+          type: array
+          items:
+            $ref: '#/components/schemas/AgentResponse'
+
+    EnvironmentLastTask:
+      type: object
+      description: Summary of the most recently created task for an environment
+      required:
+        - id
+        - title
+        - state
+        - created_at
+        - updated_at
+      properties:
+        id:
+          type: string
+          description: Unique identifier of the task
+        title:
+          type: string
+          description: Title of the task
+        state:
+          $ref: '#/components/schemas/RunState'
+        created_at:
+          type: string
+          format: date-time
+          description: When the task was created (RFC3339)
+        updated_at:
+          type: string
+          format: date-time
+          description: When the task was last updated (RFC3339)
+        started_at:
+          type: string
+          format: date-time
+          nullable: true
+          description: When the task started running (RFC3339), null if not yet started
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..0caee68
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,17088 @@
+{
+  "name": "warp-docs",
+  "version": "0.0.1",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "warp-docs",
+      "version": "0.0.1",
+      "license": "MIT",
+      "dependencies": {
+        "@astrojs/react": "^5.0.3",
+        "@astrojs/rss": "^4.0.18",
+        "@astrojs/sitemap": "^3.7.2",
+        "@astrojs/starlight": "^0.38.4",
+        "@astrojs/vercel": "^10.0.4",
+        "@kapaai/react-sdk": "^0.9.2",
+        "@radix-ui/react-popover": "^1.1.15",
+        "@vercel/analytics": "^2.0.0",
+        "@vercel/speed-insights": "^2.0.0",
+        "astro": "^6.1.8",
+        "keymatch": "^1.0.5",
+        "linkedom": "^0.18.12",
+        "react": "^19.2.4",
+        "react-dom": "^19.2.4",
+        "react-icons": "^5.6.0",
+        "react-markdown": "^10.1.0",
+        "sharp": "^0.34.2",
+        "starlight-llms-txt": "^0.8.1",
+        "starlight-sidebar-topics": "^0.7.1",
+        "turndown": "^7.2.2",
+        "turndown-plugin-gfm": "^1.0.2",
+        "yaml": "^2.8.3"
+      },
+      "devDependencies": {
+        "@astrojs/check": "^0.9.8",
+        "typescript": "^5.9.3"
+      },
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || ^24"
+      }
+    },
+    "node_modules/@astrojs/check": {
+      "version": "0.9.8",
+      "resolved": "https://registry.npmjs.org/@astrojs/check/-/check-0.9.8.tgz",
+      "integrity": "sha512-LDng8446QLS5ToKjRHd3bgUdirvemVVExV7nRyJfW2wV36xuv7vDxwy5NWN9zqeSEDgg0Tv84sP+T3yEq+Zlkw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@astrojs/language-server": "^2.16.5",
+        "chokidar": "^4.0.3",
+        "kleur": "^4.1.5",
+        "yargs": "^17.7.2"
+      },
+      "bin": {
+        "astro-check": "bin/astro-check.js"
+      },
+      "peerDependencies": {
+        "typescript": "^5.0.0"
+      }
+    },
+    "node_modules/@astrojs/check/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@astrojs/check/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/@astrojs/check/node_modules/chokidar": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+      "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/@astrojs/check/node_modules/cliui": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.1",
+        "wrap-ansi": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@astrojs/check/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@astrojs/check/node_modules/readdirp": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+      "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14.18.0"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/@astrojs/check/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@astrojs/check/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@astrojs/check/node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/@astrojs/check/node_modules/yargs": {
+      "version": "17.7.2",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+      "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+      "dev": true,
+      "license": "MIT",
+      "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"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@astrojs/check/node_modules/yargs-parser": {
+      "version": "21.1.1",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@astrojs/compiler": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-3.0.1.tgz",
+      "integrity": "sha512-z97oYbdebO5aoWzuJ/8q5hLK232+17KcLZ7cJ8BCWk6+qNzVxn/gftC0KzMBUTD8WAaBkPpNSQK6PXLnNrZ0CA==",
+      "license": "MIT"
+    },
+    "node_modules/@astrojs/internal-helpers": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.8.0.tgz",
+      "integrity": "sha512-J56GrhEiV+4dmrGLPNOl2pZjpHXAndWVyiVDYGDuw6MWKpBSEMLdFxHzeM/6sqaknw9M+HFfHZAcvi3OfT3D/w==",
+      "license": "MIT",
+      "dependencies": {
+        "picomatch": "^4.0.3"
+      }
+    },
+    "node_modules/@astrojs/language-server": {
+      "version": "2.16.6",
+      "resolved": "https://registry.npmjs.org/@astrojs/language-server/-/language-server-2.16.6.tgz",
+      "integrity": "sha512-N990lu+HSFiG57owR0XBkr02BYMgiLCshLf+4QG4v6jjSWkBeQGnzqi+E1L08xFPPJ7eEeXnxPXGLaVv5pa4Ug==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@astrojs/compiler": "^2.13.1",
+        "@astrojs/yaml2ts": "^0.2.3",
+        "@jridgewell/sourcemap-codec": "^1.5.5",
+        "@volar/kit": "~2.4.28",
+        "@volar/language-core": "~2.4.28",
+        "@volar/language-server": "~2.4.28",
+        "@volar/language-service": "~2.4.28",
+        "muggle-string": "^0.4.1",
+        "tinyglobby": "^0.2.15",
+        "volar-service-css": "0.0.70",
+        "volar-service-emmet": "0.0.70",
+        "volar-service-html": "0.0.70",
+        "volar-service-prettier": "0.0.70",
+        "volar-service-typescript": "0.0.70",
+        "volar-service-typescript-twoslash-queries": "0.0.70",
+        "volar-service-yaml": "0.0.70",
+        "vscode-html-languageservice": "^5.6.2",
+        "vscode-uri": "^3.1.0"
+      },
+      "bin": {
+        "astro-ls": "bin/nodeServer.js"
+      },
+      "peerDependencies": {
+        "prettier": "^3.0.0",
+        "prettier-plugin-astro": ">=0.11.0"
+      },
+      "peerDependenciesMeta": {
+        "prettier": {
+          "optional": true
+        },
+        "prettier-plugin-astro": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@astrojs/language-server/node_modules/@astrojs/compiler": {
+      "version": "2.13.1",
+      "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.13.1.tgz",
+      "integrity": "sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@astrojs/markdown-remark": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-7.1.0.tgz",
+      "integrity": "sha512-P+HnCsu2js3BoTc8kFmu+E9gOcFeMdPris75g+Zl4sY8+bBRbSQV6xzcBDbZ27eE7yBGEGQoqjpChx+KJYIPYQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@astrojs/internal-helpers": "0.8.0",
+        "@astrojs/prism": "4.0.1",
+        "github-slugger": "^2.0.0",
+        "hast-util-from-html": "^2.0.3",
+        "hast-util-to-text": "^4.0.2",
+        "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",
+        "retext-smartypants": "^6.2.0",
+        "shiki": "^4.0.0",
+        "smol-toml": "^1.6.0",
+        "unified": "^11.0.5",
+        "unist-util-remove-position": "^5.0.0",
+        "unist-util-visit": "^5.1.0",
+        "unist-util-visit-parents": "^6.0.2",
+        "vfile": "^6.0.3"
+      }
+    },
+    "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/core": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.0.2.tgz",
+      "integrity": "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/primitive": "4.0.2",
+        "@shikijs/types": "4.0.2",
+        "@shikijs/vscode-textmate": "^10.0.2",
+        "@types/hast": "^3.0.4",
+        "hast-util-to-html": "^9.0.5"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/engine-javascript": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.0.2.tgz",
+      "integrity": "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/types": "4.0.2",
+        "@shikijs/vscode-textmate": "^10.0.2",
+        "oniguruma-to-es": "^4.3.4"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/engine-oniguruma": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.0.2.tgz",
+      "integrity": "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/types": "4.0.2",
+        "@shikijs/vscode-textmate": "^10.0.2"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/langs": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.0.2.tgz",
+      "integrity": "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/types": "4.0.2"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/themes": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.0.2.tgz",
+      "integrity": "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/types": "4.0.2"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/types": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz",
+      "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/vscode-textmate": "^10.0.2",
+        "@types/hast": "^3.0.4"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/@astrojs/markdown-remark/node_modules/shiki": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.0.2.tgz",
+      "integrity": "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/core": "4.0.2",
+        "@shikijs/engine-javascript": "4.0.2",
+        "@shikijs/engine-oniguruma": "4.0.2",
+        "@shikijs/langs": "4.0.2",
+        "@shikijs/themes": "4.0.2",
+        "@shikijs/types": "4.0.2",
+        "@shikijs/vscode-textmate": "^10.0.2",
+        "@types/hast": "^3.0.4"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/@astrojs/mdx": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-5.0.3.tgz",
+      "integrity": "sha512-zv/OlM5sZZvyjHqJjR3FjJvoCgbxdqj3t4jO/gSEUNcck3BjdtMgNQw8UgPfAGe4yySdG4vjZ3OC5wUxhu7ckg==",
+      "license": "MIT",
+      "dependencies": {
+        "@astrojs/markdown-remark": "7.1.0",
+        "@mdx-js/mdx": "^3.1.1",
+        "acorn": "^8.16.0",
+        "es-module-lexer": "^2.0.0",
+        "estree-util-visit": "^2.0.0",
+        "hast-util-to-html": "^9.0.5",
+        "piccolore": "^0.1.3",
+        "rehype-raw": "^7.0.0",
+        "remark-gfm": "^4.0.1",
+        "remark-smartypants": "^3.0.2",
+        "source-map": "^0.7.6",
+        "unist-util-visit": "^5.1.0",
+        "vfile": "^6.0.3"
+      },
+      "engines": {
+        "node": ">=22.12.0"
+      },
+      "peerDependencies": {
+        "astro": "^6.0.0"
+      }
+    },
+    "node_modules/@astrojs/prism": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-4.0.1.tgz",
+      "integrity": "sha512-nksZQVjlferuWzhPsBpQ1JE5XuKAf1id1/9Hj4a9KG4+ofrlzxUUwX4YGQF/SuDiuiGKEnzopGOt38F3AnVWsQ==",
+      "license": "MIT",
+      "dependencies": {
+        "prismjs": "^1.30.0"
+      },
+      "engines": {
+        "node": ">=22.12.0"
+      }
+    },
+    "node_modules/@astrojs/react": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/@astrojs/react/-/react-5.0.3.tgz",
+      "integrity": "sha512-z6JXjgADH4/7e0hqcRj+dO9UQlrKmsm2ZJoVT1GzOTYY0ThQ3Znpfr8tY8XKlEHWSTUlT9LP5u4v6QpEJwLz5A==",
+      "license": "MIT",
+      "dependencies": {
+        "@astrojs/internal-helpers": "0.8.0",
+        "@vitejs/plugin-react": "^5.2.0",
+        "devalue": "^5.6.4",
+        "ultrahtml": "^1.6.0",
+        "vite": "^7.3.1"
+      },
+      "engines": {
+        "node": ">=22.12.0"
+      },
+      "peerDependencies": {
+        "@types/react": "^17.0.50 || ^18.0.21 || ^19.0.0",
+        "@types/react-dom": "^17.0.17 || ^18.0.6 || ^19.0.0",
+        "react": "^17.0.2 || ^18.0.0 || ^19.0.0",
+        "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0"
+      }
+    },
+    "node_modules/@astrojs/rss": {
+      "version": "4.0.18",
+      "resolved": "https://registry.npmjs.org/@astrojs/rss/-/rss-4.0.18.tgz",
+      "integrity": "sha512-wc5DwKlbTEdgVAWnHy8krFTeQ42t1v/DJqeq5HtulYK3FYHE4krtRGjoyhS3eXXgfdV6Raoz2RU3wrMTFAitRg==",
+      "license": "MIT",
+      "dependencies": {
+        "fast-xml-parser": "^5.5.7",
+        "piccolore": "^0.1.3",
+        "zod": "^4.3.6"
+      }
+    },
+    "node_modules/@astrojs/sitemap": {
+      "version": "3.7.2",
+      "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.7.2.tgz",
+      "integrity": "sha512-PqkzkcZTb5ICiyIR8VoKbIAP/laNRXi5tw616N1Ckk+40oNB8Can1AzVV56lrbC5GKSZFCyJYUVYqVivMisvpA==",
+      "license": "MIT",
+      "dependencies": {
+        "sitemap": "^9.0.0",
+        "stream-replace-string": "^2.0.0",
+        "zod": "^4.3.6"
+      }
+    },
+    "node_modules/@astrojs/starlight": {
+      "version": "0.38.4",
+      "resolved": "https://registry.npmjs.org/@astrojs/starlight/-/starlight-0.38.4.tgz",
+      "integrity": "sha512-TGFIr2aVC+gcZCPQzJOO4ZnA/yL3jRnsUDcKlVdEhxhxaOQnWr9lZ9MRScg9zU6uh3HVeZAmmjkLCdTlHdcaZA==",
+      "license": "MIT",
+      "dependencies": {
+        "@astrojs/markdown-remark": "^7.0.0",
+        "@astrojs/mdx": "^5.0.0",
+        "@astrojs/sitemap": "^3.7.1",
+        "@pagefind/default-ui": "^1.3.0",
+        "@types/hast": "^3.0.4",
+        "@types/js-yaml": "^4.0.9",
+        "@types/mdast": "^4.0.4",
+        "astro-expressive-code": "^0.41.6",
+        "bcp-47": "^2.1.0",
+        "hast-util-from-html": "^2.0.1",
+        "hast-util-select": "^6.0.2",
+        "hast-util-to-string": "^3.0.0",
+        "hastscript": "^9.0.0",
+        "i18next": "^23.11.5",
+        "js-yaml": "^4.1.0",
+        "klona": "^2.0.6",
+        "magic-string": "^0.30.17",
+        "mdast-util-directive": "^3.0.0",
+        "mdast-util-to-markdown": "^2.1.0",
+        "mdast-util-to-string": "^4.0.0",
+        "pagefind": "^1.3.0",
+        "rehype": "^13.0.1",
+        "rehype-format": "^5.0.0",
+        "remark-directive": "^3.0.0",
+        "ultrahtml": "^1.6.0",
+        "unified": "^11.0.5",
+        "unist-util-visit": "^5.0.0",
+        "vfile": "^6.0.2"
+      },
+      "peerDependencies": {
+        "astro": "^6.0.0"
+      }
+    },
+    "node_modules/@astrojs/telemetry": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.1.tgz",
+      "integrity": "sha512-7fcIxXS9J4ls5tr8b3ww9rbAIz2+HrhNJYZdkAhhB4za/I5IZ/60g+Bs8q7zwG0tOIZfNB4JWhVJ1Qkl/OrNCw==",
+      "license": "MIT",
+      "dependencies": {
+        "ci-info": "^4.4.0",
+        "dlv": "^1.1.3",
+        "dset": "^3.1.4",
+        "is-docker": "^4.0.0",
+        "is-wsl": "^3.1.1",
+        "which-pm-runs": "^1.1.0"
+      },
+      "engines": {
+        "node": "18.20.8 || ^20.3.0 || >=22.0.0"
+      }
+    },
+    "node_modules/@astrojs/telemetry/node_modules/is-docker": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-4.0.0.tgz",
+      "integrity": "sha512-LHE+wROyG/Y/0ZnbktRCoTix2c1RhgWaZraMZ8o1Q7zCh0VSrICJQO5oqIIISrcSBtrXv0o233w1IYwsWCjTzA==",
+      "license": "MIT",
+      "bin": {
+        "is-docker": "cli.js"
+      },
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@astrojs/vercel": {
+      "version": "10.0.4",
+      "resolved": "https://registry.npmjs.org/@astrojs/vercel/-/vercel-10.0.4.tgz",
+      "integrity": "sha512-+kxbLKCimr9ivqXTldE3JyXB6Ks7WU6C8jcZGt+CLM9N1IVCWck9ustz3Hd/OGROQpzRATLVvrlbwyeM7Gycpw==",
+      "license": "MIT",
+      "dependencies": {
+        "@astrojs/internal-helpers": "0.8.0",
+        "@vercel/analytics": "^1.6.1",
+        "@vercel/functions": "^3.4.3",
+        "@vercel/nft": "^1.3.2",
+        "@vercel/routing-utils": "^5.3.3",
+        "esbuild": "^0.27.3",
+        "tinyglobby": "^0.2.15"
+      },
+      "peerDependencies": {
+        "astro": "^6.0.0"
+      }
+    },
+    "node_modules/@astrojs/vercel/node_modules/@vercel/analytics": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.6.1.tgz",
+      "integrity": "sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==",
+      "license": "MPL-2.0",
+      "peerDependencies": {
+        "@remix-run/react": "^2",
+        "@sveltejs/kit": "^1 || ^2",
+        "next": ">= 13",
+        "react": "^18 || ^19 || ^19.0.0-rc",
+        "svelte": ">= 4",
+        "vue": "^3",
+        "vue-router": "^4"
+      },
+      "peerDependenciesMeta": {
+        "@remix-run/react": {
+          "optional": true
+        },
+        "@sveltejs/kit": {
+          "optional": true
+        },
+        "next": {
+          "optional": true
+        },
+        "react": {
+          "optional": true
+        },
+        "svelte": {
+          "optional": true
+        },
+        "vue": {
+          "optional": true
+        },
+        "vue-router": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@astrojs/yaml2ts": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/@astrojs/yaml2ts/-/yaml2ts-0.2.3.tgz",
+      "integrity": "sha512-PJzRmgQzUxI2uwpdX2lXSHtP4G8ocp24/t+bZyf5Fy0SZLSF9f9KXZoMlFM/XCGue+B0nH/2IZ7FpBYQATBsCg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "yaml": "^2.8.2"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.29.0",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
+      "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.28.5",
+        "js-tokens": "^4.0.0",
+        "picocolors": "^1.1.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/compat-data": {
+      "version": "7.29.0",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz",
+      "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/core": {
+      "version": "7.29.0",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
+      "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.29.0",
+        "@babel/generator": "^7.29.0",
+        "@babel/helper-compilation-targets": "^7.28.6",
+        "@babel/helper-module-transforms": "^7.28.6",
+        "@babel/helpers": "^7.28.6",
+        "@babel/parser": "^7.29.0",
+        "@babel/template": "^7.28.6",
+        "@babel/traverse": "^7.29.0",
+        "@babel/types": "^7.29.0",
+        "@jridgewell/remapping": "^2.3.5",
+        "convert-source-map": "^2.0.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.2",
+        "json5": "^2.2.3",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/babel"
+      }
+    },
+    "node_modules/@babel/core/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/generator": {
+      "version": "7.29.1",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
+      "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.29.0",
+        "@babel/types": "^7.29.0",
+        "@jridgewell/gen-mapping": "^0.3.12",
+        "@jridgewell/trace-mapping": "^0.3.28",
+        "jsesc": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-annotate-as-pure": {
+      "version": "7.27.3",
+      "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz",
+      "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/types": "^7.27.3"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
+      "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/compat-data": "^7.28.6",
+        "@babel/helper-validator-option": "^7.27.1",
+        "browserslist": "^4.24.0",
+        "lru-cache": "^5.1.1",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+      "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+      "license": "ISC",
+      "dependencies": {
+        "yallist": "^3.0.2"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+      "license": "ISC"
+    },
+    "node_modules/@babel/helper-create-class-features-plugin": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz",
+      "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.27.3",
+        "@babel/helper-member-expression-to-functions": "^7.28.5",
+        "@babel/helper-optimise-call-expression": "^7.27.1",
+        "@babel/helper-replace-supers": "^7.28.6",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
+        "@babel/traverse": "^7.28.6",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "license": "ISC",
+      "peer": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/helper-globals": {
+      "version": "7.28.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+      "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-member-expression-to-functions": {
+      "version": "7.28.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz",
+      "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/traverse": "^7.28.5",
+        "@babel/types": "^7.28.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-imports": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
+      "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/traverse": "^7.28.6",
+        "@babel/types": "^7.28.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-transforms": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
+      "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.28.6",
+        "@babel/helper-validator-identifier": "^7.28.5",
+        "@babel/traverse": "^7.28.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-optimise-call-expression": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz",
+      "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/types": "^7.27.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-plugin-utils": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
+      "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-replace-supers": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz",
+      "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-member-expression-to-functions": "^7.28.5",
+        "@babel/helper-optimise-call-expression": "^7.27.1",
+        "@babel/traverse": "^7.28.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz",
+      "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/traverse": "^7.27.1",
+        "@babel/types": "^7.27.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-string-parser": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+      "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.28.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+      "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-option": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+      "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helpers": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz",
+      "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/template": "^7.28.6",
+        "@babel/types": "^7.28.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.29.2",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz",
+      "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.29.0"
+      },
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-jsx": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz",
+      "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.28.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-typescript": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz",
+      "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.28.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-react-jsx-self": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
+      "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.27.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-react-jsx-source": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
+      "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.27.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-typescript": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz",
+      "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.27.3",
+        "@babel/helper-create-class-features-plugin": "^7.28.6",
+        "@babel/helper-plugin-utils": "^7.28.6",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
+        "@babel/plugin-syntax-typescript": "^7.28.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/runtime": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz",
+      "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/template": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
+      "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.28.6",
+        "@babel/parser": "^7.28.6",
+        "@babel/types": "^7.28.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/traverse": {
+      "version": "7.29.0",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
+      "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.29.0",
+        "@babel/generator": "^7.29.0",
+        "@babel/helper-globals": "^7.28.0",
+        "@babel/parser": "^7.29.0",
+        "@babel/template": "^7.28.6",
+        "@babel/types": "^7.29.0",
+        "debug": "^4.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/types": {
+      "version": "7.29.0",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
+      "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-string-parser": "^7.27.1",
+        "@babel/helper-validator-identifier": "^7.28.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@bomb.sh/tab": {
+      "version": "0.0.14",
+      "resolved": "https://registry.npmjs.org/@bomb.sh/tab/-/tab-0.0.14.tgz",
+      "integrity": "sha512-cHMk2LI430MVoX1unTt9oK1iZzQS4CYDz97MSxKLNErW69T43Z2QLFTpdS/3jVOIKrIADWfuxQ+nQNJkNV7E4w==",
+      "license": "MIT",
+      "peer": true,
+      "bin": {
+        "tab": "dist/bin/cli.mjs"
+      },
+      "peerDependencies": {
+        "cac": "^6.7.14",
+        "citty": "^0.1.6 || ^0.2.0",
+        "commander": "^13.1.0"
+      },
+      "peerDependenciesMeta": {
+        "cac": {
+          "optional": true
+        },
+        "citty": {
+          "optional": true
+        },
+        "commander": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@capsizecss/unpack": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@capsizecss/unpack/-/unpack-4.0.0.tgz",
+      "integrity": "sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==",
+      "license": "MIT",
+      "dependencies": {
+        "fontkitten": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@clack/core": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.1.0.tgz",
+      "integrity": "sha512-SVcm4Dqm2ukn64/8Gub2wnlA5nS2iWJyCkdNHcvNHPIeBTGojpdJ+9cZKwLfmqy7irD4N5qLteSilJlE0WLAtA==",
+      "license": "MIT",
+      "dependencies": {
+        "sisteransi": "^1.0.5"
+      }
+    },
+    "node_modules/@clack/prompts": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.1.0.tgz",
+      "integrity": "sha512-pkqbPGtohJAvm4Dphs2M8xE29ggupihHdy1x84HNojZuMtFsHiUlRvqD24tM2+XmI+61LlfNceM3Wr7U5QES5g==",
+      "license": "MIT",
+      "dependencies": {
+        "@clack/core": "1.1.0",
+        "sisteransi": "^1.0.5"
+      }
+    },
+    "node_modules/@cloudflare/kv-asset-handler": {
+      "version": "0.4.2",
+      "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.2.tgz",
+      "integrity": "sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==",
+      "license": "MIT OR Apache-2.0",
+      "peer": true,
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@colordx/core": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/@colordx/core/-/core-5.2.0.tgz",
+      "integrity": "sha512-wifnqsGCXRh+lJdX4975nKEPJaSk7k8rMiA/VeGrS4tOTn06WZrow6cUA7wFJKPXfcqj0rXeH4BMgGoKZvBf7g==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@ctrl/tinycolor": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-4.2.0.tgz",
+      "integrity": "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/@dxup/nuxt": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/@dxup/nuxt/-/nuxt-0.4.0.tgz",
+      "integrity": "sha512-28LDotpr9G2knUse3cQYsOo6NJq5yhABv4ByRVRYJUmzf9Q31DI7rpRek4POlKy1aAcYyKgu5J2616pyqLohYg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@dxup/unimport": "^0.1.2",
+        "@nuxt/kit": "^4.2.2",
+        "chokidar": "^5.0.0",
+        "pathe": "^2.0.3",
+        "tinyglobby": "^0.2.15"
+      },
+      "peerDependencies": {
+        "typescript": "*"
+      }
+    },
+    "node_modules/@dxup/unimport": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/@dxup/unimport/-/unimport-0.1.2.tgz",
+      "integrity": "sha512-/B8YJGPzaYq1NbsQmwgP8EZqg40NpTw4ZB3suuI0TplbxKHeK94jeaawLmVhCv+YwUnOpiWEz9U6SeThku/8JQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@emmetio/abbreviation": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-2.3.3.tgz",
+      "integrity": "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@emmetio/scanner": "^1.0.4"
+      }
+    },
+    "node_modules/@emmetio/css-abbreviation": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/@emmetio/css-abbreviation/-/css-abbreviation-2.1.8.tgz",
+      "integrity": "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@emmetio/scanner": "^1.0.4"
+      }
+    },
+    "node_modules/@emmetio/css-parser": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/@emmetio/css-parser/-/css-parser-0.4.1.tgz",
+      "integrity": "sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@emmetio/stream-reader": "^2.2.0",
+        "@emmetio/stream-reader-utils": "^0.1.0"
+      }
+    },
+    "node_modules/@emmetio/html-matcher": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@emmetio/html-matcher/-/html-matcher-1.3.0.tgz",
+      "integrity": "sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "@emmetio/scanner": "^1.0.0"
+      }
+    },
+    "node_modules/@emmetio/scanner": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/@emmetio/scanner/-/scanner-1.0.4.tgz",
+      "integrity": "sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@emmetio/stream-reader": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@emmetio/stream-reader/-/stream-reader-2.2.0.tgz",
+      "integrity": "sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@emmetio/stream-reader-utils": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/@emmetio/stream-reader-utils/-/stream-reader-utils-0.1.0.tgz",
+      "integrity": "sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@emnapi/core": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
+      "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "@emnapi/wasi-threads": "1.2.1",
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@emnapi/runtime": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz",
+      "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@emnapi/wasi-threads": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
+      "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@esbuild/aix-ppc64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz",
+      "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==",
+      "cpu": [
+        "ppc64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "aix"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-arm": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz",
+      "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-arm64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz",
+      "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-x64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz",
+      "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/darwin-arm64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz",
+      "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/darwin-x64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz",
+      "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz",
+      "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/freebsd-x64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz",
+      "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-arm": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz",
+      "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-arm64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz",
+      "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-ia32": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz",
+      "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==",
+      "cpu": [
+        "ia32"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-loong64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz",
+      "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==",
+      "cpu": [
+        "loong64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-mips64el": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz",
+      "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==",
+      "cpu": [
+        "mips64el"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-ppc64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz",
+      "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==",
+      "cpu": [
+        "ppc64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-riscv64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz",
+      "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==",
+      "cpu": [
+        "riscv64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-s390x": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz",
+      "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==",
+      "cpu": [
+        "s390x"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-x64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz",
+      "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/netbsd-arm64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz",
+      "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/netbsd-x64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz",
+      "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openbsd-arm64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz",
+      "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openbsd-x64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz",
+      "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openharmony-arm64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz",
+      "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openharmony"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/sunos-x64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz",
+      "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-arm64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz",
+      "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-ia32": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz",
+      "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==",
+      "cpu": [
+        "ia32"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-x64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz",
+      "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@expressive-code/core": {
+      "version": "0.41.7",
+      "resolved": "https://registry.npmjs.org/@expressive-code/core/-/core-0.41.7.tgz",
+      "integrity": "sha512-ck92uZYZ9Wba2zxkiZLsZGi9N54pMSAVdrI9uW3Oo9AtLglD5RmrdTwbYPCT2S/jC36JGB2i+pnQtBm/Ib2+dg==",
+      "license": "MIT",
+      "dependencies": {
+        "@ctrl/tinycolor": "^4.0.4",
+        "hast-util-select": "^6.0.2",
+        "hast-util-to-html": "^9.0.1",
+        "hast-util-to-text": "^4.0.1",
+        "hastscript": "^9.0.0",
+        "postcss": "^8.4.38",
+        "postcss-nested": "^6.0.1",
+        "unist-util-visit": "^5.0.0",
+        "unist-util-visit-parents": "^6.0.1"
+      }
+    },
+    "node_modules/@expressive-code/plugin-frames": {
+      "version": "0.41.7",
+      "resolved": "https://registry.npmjs.org/@expressive-code/plugin-frames/-/plugin-frames-0.41.7.tgz",
+      "integrity": "sha512-diKtxjQw/979cTglRFaMCY/sR6hWF0kSMg8jsKLXaZBSfGS0I/Hoe7Qds3vVEgeoW+GHHQzMcwvgx/MOIXhrTA==",
+      "license": "MIT",
+      "dependencies": {
+        "@expressive-code/core": "^0.41.7"
+      }
+    },
+    "node_modules/@expressive-code/plugin-shiki": {
+      "version": "0.41.7",
+      "resolved": "https://registry.npmjs.org/@expressive-code/plugin-shiki/-/plugin-shiki-0.41.7.tgz",
+      "integrity": "sha512-DL605bLrUOgqTdZ0Ot5MlTaWzppRkzzqzeGEu7ODnHF39IkEBbFdsC7pbl3LbUQ1DFtnfx6rD54k/cdofbW6KQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@expressive-code/core": "^0.41.7",
+        "shiki": "^3.2.2"
+      }
+    },
+    "node_modules/@expressive-code/plugin-text-markers": {
+      "version": "0.41.7",
+      "resolved": "https://registry.npmjs.org/@expressive-code/plugin-text-markers/-/plugin-text-markers-0.41.7.tgz",
+      "integrity": "sha512-Ewpwuc5t6eFdZmWlFyeuy3e1PTQC0jFvw2Q+2bpcWXbOZhPLsT7+h8lsSIJxb5mS7wZko7cKyQ2RLYDyK6Fpmw==",
+      "license": "MIT",
+      "dependencies": {
+        "@expressive-code/core": "^0.41.7"
+      }
+    },
+    "node_modules/@fingerprintjs/fingerprintjs-pro": {
+      "version": "3.12.8",
+      "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro/-/fingerprintjs-pro-3.12.8.tgz",
+      "integrity": "sha512-6BEMtAkfvMTnTLpHaS6q+lW11msE9vFzHheE95SD/+X21QKGVsMGlel7lBG2ClGHHdqpFNO+nNKvuIl/xdPgng==",
+      "license": "SEE LICENSE IN LICENSE"
+    },
+    "node_modules/@fingerprintjs/fingerprintjs-pro-react": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro-react/-/fingerprintjs-pro-react-2.7.1.tgz",
+      "integrity": "sha512-/vQtjd+P8C9OFU8Wvd4AScoNRP6RKDIvYQwwaY/b31PcRBNDqVV9xm7DDBg9uTdDv4KZM3ubEY4JyyVWkXs4EA==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "dependencies": {
+        "@fingerprintjs/fingerprintjs-pro-spa": "^1.3.3",
+        "fast-deep-equal": "3.1.3"
+      }
+    },
+    "node_modules/@fingerprintjs/fingerprintjs-pro-spa": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro-spa/-/fingerprintjs-pro-spa-1.3.3.tgz",
+      "integrity": "sha512-jM5k30S9RT/WW6gnmNWACc7UHeK1md9NbZg8kUsdxvPtDeW8xKnA6tb58Rqfkg6kvqHTq5aHFzw9hgsTH3DbNQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@fingerprintjs/fingerprintjs-pro": "^3.12.0",
+        "tslib": "^2.7.0"
+      }
+    },
+    "node_modules/@floating-ui/core": {
+      "version": "1.7.5",
+      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz",
+      "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@floating-ui/utils": "^0.2.11"
+      }
+    },
+    "node_modules/@floating-ui/dom": {
+      "version": "1.7.6",
+      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz",
+      "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@floating-ui/core": "^1.7.5",
+        "@floating-ui/utils": "^0.2.11"
+      }
+    },
+    "node_modules/@floating-ui/react-dom": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz",
+      "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==",
+      "license": "MIT",
+      "dependencies": {
+        "@floating-ui/dom": "^1.7.6"
+      },
+      "peerDependencies": {
+        "react": ">=16.8.0",
+        "react-dom": ">=16.8.0"
+      }
+    },
+    "node_modules/@floating-ui/utils": {
+      "version": "0.2.11",
+      "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz",
+      "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==",
+      "license": "MIT"
+    },
+    "node_modules/@hcaptcha/loader": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/@hcaptcha/loader/-/loader-2.3.0.tgz",
+      "integrity": "sha512-i4lnNxKBe+COf3R1nFZEWaZoHIoJjvDgWqvcNrdZq8ehoSNMN6KVZ56dcQ02qKie2h3+BkbkwlJA9DOIuLlK/g==",
+      "license": "MIT"
+    },
+    "node_modules/@hcaptcha/react-hcaptcha": {
+      "version": "1.17.4",
+      "resolved": "https://registry.npmjs.org/@hcaptcha/react-hcaptcha/-/react-hcaptcha-1.17.4.tgz",
+      "integrity": "sha512-rIvgesG1N7SS9sAYYHFoWm+nXqRrxq7RcA9z2pKkDWV+S1GdfmrTNYA1aPyVWVe3eowphTCwyDJvl97Swwy0mw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.17.9",
+        "@hcaptcha/loader": "^2.3.0"
+      },
+      "peerDependencies": {
+        "react": ">= 16.3.0",
+        "react-dom": ">= 16.3.0"
+      }
+    },
+    "node_modules/@img/colour": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz",
+      "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@img/sharp-darwin-arm64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
+      "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-darwin-arm64": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-darwin-x64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
+      "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-darwin-x64": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-libvips-darwin-arm64": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
+      "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-darwin-x64": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
+      "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linux-arm": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
+      "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linux-arm64": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
+      "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linux-ppc64": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
+      "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
+      "cpu": [
+        "ppc64"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linux-riscv64": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
+      "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
+      "cpu": [
+        "riscv64"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linux-s390x": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
+      "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
+      "cpu": [
+        "s390x"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linux-x64": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
+      "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
+      "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linuxmusl-x64": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
+      "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-linux-arm": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
+      "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-linux-arm": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-linux-arm64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
+      "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-linux-arm64": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-linux-ppc64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
+      "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
+      "cpu": [
+        "ppc64"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-linux-ppc64": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-linux-riscv64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
+      "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
+      "cpu": [
+        "riscv64"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-linux-riscv64": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-linux-s390x": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
+      "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
+      "cpu": [
+        "s390x"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-linux-s390x": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-linux-x64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
+      "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-linux-x64": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-linuxmusl-arm64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
+      "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-linuxmusl-x64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
+      "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-linuxmusl-x64": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-wasm32": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
+      "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
+      "cpu": [
+        "wasm32"
+      ],
+      "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+      "optional": true,
+      "dependencies": {
+        "@emnapi/runtime": "^1.7.0"
+      },
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-win32-arm64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
+      "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "Apache-2.0 AND LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-win32-ia32": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
+      "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
+      "cpu": [
+        "ia32"
+      ],
+      "license": "Apache-2.0 AND LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-win32-x64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
+      "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "Apache-2.0 AND LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@ioredis/commands": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.5.1.tgz",
+      "integrity": "sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@isaacs/cliui": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+      "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+      "license": "ISC",
+      "peer": true,
+      "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"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@isaacs/fs-minipass": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
+      "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+      "license": "ISC",
+      "dependencies": {
+        "minipass": "^7.0.4"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.13",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+      "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.5.0",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      }
+    },
+    "node_modules/@jridgewell/remapping": {
+      "version": "2.3.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+      "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/source-map": {
+      "version": "0.3.11",
+      "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
+      "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.25"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+      "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+      "license": "MIT"
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.31",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+      "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
+      }
+    },
+    "node_modules/@kapaai/react-sdk": {
+      "version": "0.9.2",
+      "resolved": "https://registry.npmjs.org/@kapaai/react-sdk/-/react-sdk-0.9.2.tgz",
+      "integrity": "sha512-PeqgKL6d0yIkkmPn+1O8TBjH7KGx5HNiH7fhGl0FEV2MfJZBzWNvAOdOm/34VLdpb2Nawe3H1gSURdJ0DG6z7Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@fingerprintjs/fingerprintjs-pro-react": "^2.7.0",
+        "@hcaptcha/react-hcaptcha": "^1.12.0",
+        "@tanstack/react-query": "^5.74.3",
+        "js-cookie": "^3.0.5",
+        "tldts": "^7.0.7"
+      },
+      "peerDependencies": {
+        "react": ">=17.0.0",
+        "react-dom": ">=17.0.0"
+      }
+    },
+    "node_modules/@kwsites/file-exists": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz",
+      "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "debug": "^4.1.1"
+      }
+    },
+    "node_modules/@kwsites/promise-deferred": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz",
+      "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@mapbox/node-pre-gyp": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-2.0.3.tgz",
+      "integrity": "sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==",
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "consola": "^3.2.3",
+        "detect-libc": "^2.0.0",
+        "https-proxy-agent": "^7.0.5",
+        "node-fetch": "^2.6.7",
+        "nopt": "^8.0.0",
+        "semver": "^7.5.3",
+        "tar": "^7.4.0"
+      },
+      "bin": {
+        "node-pre-gyp": "bin/node-pre-gyp"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@mdx-js/mdx": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz",
+      "integrity": "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==",
+      "license": "MIT",
+      "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"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/@mixmark-io/domino": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz",
+      "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==",
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/@napi-rs/wasm-runtime": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
+      "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "@tybys/wasm-util": "^0.10.1"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/Brooooooklyn"
+      },
+      "peerDependencies": {
+        "@emnapi/core": "^1.7.1",
+        "@emnapi/runtime": "^1.7.1"
+      }
+    },
+    "node_modules/@nodable/entities": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.0.tgz",
+      "integrity": "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/nodable"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nuxt/cli": {
+      "version": "3.34.0",
+      "resolved": "https://registry.npmjs.org/@nuxt/cli/-/cli-3.34.0.tgz",
+      "integrity": "sha512-KVI4xSo96UtUUbmxr9ouWTytbj1LzTw5alsM4vC/gSY/l8kPMRAlq0XpNSAVTDJyALzLY70WhaIMX24LJLpdFw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@bomb.sh/tab": "^0.0.14",
+        "@clack/prompts": "^1.1.0",
+        "c12": "^3.3.3",
+        "citty": "^0.2.1",
+        "confbox": "^0.2.4",
+        "consola": "^3.4.2",
+        "debug": "^4.4.3",
+        "defu": "^6.1.4",
+        "exsolve": "^1.0.8",
+        "fuse.js": "^7.1.0",
+        "fzf": "^0.5.2",
+        "giget": "^3.1.2",
+        "jiti": "^2.6.1",
+        "listhen": "^1.9.0",
+        "nypm": "^0.6.5",
+        "ofetch": "^1.5.1",
+        "ohash": "^2.0.11",
+        "pathe": "^2.0.3",
+        "perfect-debounce": "^2.1.0",
+        "pkg-types": "^2.3.0",
+        "scule": "^1.3.0",
+        "semver": "^7.7.4",
+        "srvx": "^0.11.9",
+        "std-env": "^3.10.0",
+        "tinyclip": "^0.1.12",
+        "tinyexec": "^1.0.2",
+        "ufo": "^1.6.3",
+        "youch": "^4.1.0"
+      },
+      "bin": {
+        "nuxi": "bin/nuxi.mjs",
+        "nuxi-ng": "bin/nuxi.mjs",
+        "nuxt": "bin/nuxi.mjs",
+        "nuxt-cli": "bin/nuxi.mjs"
+      },
+      "engines": {
+        "node": "^16.14.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "@nuxt/schema": "^4.3.1"
+      },
+      "peerDependenciesMeta": {
+        "@nuxt/schema": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@nuxt/cli/node_modules/std-env": {
+      "version": "3.10.0",
+      "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz",
+      "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@nuxt/devalue": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@nuxt/devalue/-/devalue-2.0.2.tgz",
+      "integrity": "sha512-GBzP8zOc7CGWyFQS6dv1lQz8VVpz5C2yRszbXufwG/9zhStTIH50EtD87NmWbTMwXDvZLNg8GIpb1UFdH93JCA==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@nuxt/devtools": {
+      "version": "3.2.4",
+      "resolved": "https://registry.npmjs.org/@nuxt/devtools/-/devtools-3.2.4.tgz",
+      "integrity": "sha512-VPbFy7hlPzWpEZk4BsuVpNuHq1ZYGV9xezjb7/NGuePuNLqeNn74YZugU+PCtva7OwKhEeTXmMK0Mqo/6+nwNA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@nuxt/devtools-kit": "3.2.4",
+        "@nuxt/devtools-wizard": "3.2.4",
+        "@nuxt/kit": "^4.4.2",
+        "@vue/devtools-core": "^8.1.0",
+        "@vue/devtools-kit": "^8.1.0",
+        "birpc": "^4.0.0",
+        "consola": "^3.4.2",
+        "destr": "^2.0.5",
+        "error-stack-parser-es": "^1.0.5",
+        "execa": "^8.0.1",
+        "fast-npm-meta": "^1.4.2",
+        "get-port-please": "^3.2.0",
+        "hookable": "^6.1.0",
+        "image-meta": "^0.2.2",
+        "is-installed-globally": "^1.0.0",
+        "launch-editor": "^2.13.1",
+        "local-pkg": "^1.1.2",
+        "magicast": "^0.5.2",
+        "nypm": "^0.6.5",
+        "ohash": "^2.0.11",
+        "pathe": "^2.0.3",
+        "perfect-debounce": "^2.1.0",
+        "pkg-types": "^2.3.0",
+        "semver": "^7.7.4",
+        "simple-git": "^3.33.0",
+        "sirv": "^3.0.2",
+        "structured-clone-es": "^2.0.0",
+        "tinyglobby": "^0.2.15",
+        "vite-plugin-inspect": "^11.3.3",
+        "vite-plugin-vue-tracer": "^1.3.0",
+        "which": "^6.0.1",
+        "ws": "^8.19.0"
+      },
+      "bin": {
+        "devtools": "cli.mjs"
+      },
+      "peerDependencies": {
+        "@vitejs/devtools": "*",
+        "vite": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "@vitejs/devtools": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@nuxt/devtools-kit": {
+      "version": "3.2.4",
+      "resolved": "https://registry.npmjs.org/@nuxt/devtools-kit/-/devtools-kit-3.2.4.tgz",
+      "integrity": "sha512-Yxy2Xgmq5hf3dQy983V0xh0OJV2mYwRZz9eVIGc3EaribdFGPDNGMMbYqX9qCty3Pbxn/bCF3J0UyPaNlHVayQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@nuxt/kit": "^4.4.2",
+        "execa": "^8.0.1"
+      },
+      "peerDependencies": {
+        "vite": ">=6.0"
+      }
+    },
+    "node_modules/@nuxt/devtools-wizard": {
+      "version": "3.2.4",
+      "resolved": "https://registry.npmjs.org/@nuxt/devtools-wizard/-/devtools-wizard-3.2.4.tgz",
+      "integrity": "sha512-5tu2+Quu9XTxwtpzM8CUN0UKn/bzZIfJcoGd+at5Yy1RiUQJ4E52tRK0idW1rMSUDkbkvX3dSnu8Tpj7SAtWdQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@clack/prompts": "^1.1.0",
+        "consola": "^3.4.2",
+        "diff": "^8.0.3",
+        "execa": "^8.0.1",
+        "magicast": "^0.5.2",
+        "pathe": "^2.0.3",
+        "pkg-types": "^2.3.0",
+        "semver": "^7.7.4"
+      },
+      "bin": {
+        "devtools-wizard": "cli.mjs"
+      }
+    },
+    "node_modules/@nuxt/kit": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.4.2.tgz",
+      "integrity": "sha512-5+IPRNX2CjkBhuWUwz0hBuLqiaJPRoKzQ+SvcdrQDbAyE+VDeFt74VpSFr5/R0ujrK4b+XnSHUJWdS72w6hsog==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "c12": "^3.3.3",
+        "consola": "^3.4.2",
+        "defu": "^6.1.4",
+        "destr": "^2.0.5",
+        "errx": "^0.1.0",
+        "exsolve": "^1.0.8",
+        "ignore": "^7.0.5",
+        "jiti": "^2.6.1",
+        "klona": "^2.0.6",
+        "mlly": "^1.8.1",
+        "ohash": "^2.0.11",
+        "pathe": "^2.0.3",
+        "pkg-types": "^2.3.0",
+        "rc9": "^3.0.0",
+        "scule": "^1.3.0",
+        "semver": "^7.7.4",
+        "tinyglobby": "^0.2.15",
+        "ufo": "^1.6.3",
+        "unctx": "^2.5.0",
+        "untyped": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=18.12.0"
+      }
+    },
+    "node_modules/@nuxt/nitro-server": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/@nuxt/nitro-server/-/nitro-server-4.4.2.tgz",
+      "integrity": "sha512-iMTfraWcpA0MuEnnEI8JFK/4DODY4ss1CfB8m3sBVOqW9jpY1Z6hikxzrtN+CadtepW2aOI5d8TdX5hab+Sb4Q==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/plugin-syntax-typescript": "^7.28.6",
+        "@nuxt/devalue": "^2.0.2",
+        "@nuxt/kit": "4.4.2",
+        "@unhead/vue": "^2.1.12",
+        "@vue/shared": "^3.5.30",
+        "consola": "^3.4.2",
+        "defu": "^6.1.4",
+        "destr": "^2.0.5",
+        "devalue": "^5.6.3",
+        "errx": "^0.1.0",
+        "escape-string-regexp": "^5.0.0",
+        "exsolve": "^1.0.8",
+        "h3": "^1.15.6",
+        "impound": "^1.1.5",
+        "klona": "^2.0.6",
+        "mocked-exports": "^0.1.1",
+        "nitropack": "^2.13.1",
+        "nypm": "^0.6.5",
+        "ohash": "^2.0.11",
+        "pathe": "^2.0.3",
+        "pkg-types": "^2.3.0",
+        "rou3": "^0.8.1",
+        "std-env": "^4.0.0",
+        "ufo": "^1.6.3",
+        "unctx": "^2.5.0",
+        "unstorage": "^1.17.4",
+        "vue": "^3.5.30",
+        "vue-bundle-renderer": "^2.2.0",
+        "vue-devtools-stub": "^0.1.0"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "peerDependencies": {
+        "@babel/plugin-proposal-decorators": "^7.25.0",
+        "@rollup/plugin-babel": "^6.0.0 || ^7.0.0",
+        "nuxt": "^4.4.2"
+      },
+      "peerDependenciesMeta": {
+        "@babel/plugin-proposal-decorators": {
+          "optional": true
+        },
+        "@rollup/plugin-babel": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@nuxt/schema": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-4.4.2.tgz",
+      "integrity": "sha512-/q6C7Qhiricgi+PKR7ovBnJlKTL0memCbA1CzRT+itCW/oeYzUfeMdQ35mGntlBoyRPNrMXbzuSUhfDbSCU57w==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@vue/shared": "^3.5.30",
+        "defu": "^6.1.4",
+        "pathe": "^2.0.3",
+        "pkg-types": "^2.3.0",
+        "std-env": "^4.0.0"
+      },
+      "engines": {
+        "node": "^14.18.0 || >=16.10.0"
+      }
+    },
+    "node_modules/@nuxt/telemetry": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@nuxt/telemetry/-/telemetry-2.8.0.tgz",
+      "integrity": "sha512-zAwXY24KYvpLTmiV+osagd2EHkfs5IF+7oDZYTQoit5r0kPlwaCNlzHp5I/wUAWT4LBw6lG8gZ6bWidAdv/erQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "citty": "^0.2.1",
+        "consola": "^3.4.2",
+        "ofetch": "^2.0.0-alpha.3",
+        "rc9": "^3.0.0",
+        "std-env": "^4.0.0"
+      },
+      "bin": {
+        "nuxt-telemetry": "bin/nuxt-telemetry.mjs"
+      },
+      "engines": {
+        "node": ">=18.12.0"
+      },
+      "peerDependencies": {
+        "@nuxt/kit": ">=3.0.0"
+      }
+    },
+    "node_modules/@nuxt/telemetry/node_modules/ofetch": {
+      "version": "2.0.0-alpha.3",
+      "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-2.0.0-alpha.3.tgz",
+      "integrity": "sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@nuxt/vite-builder": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/@nuxt/vite-builder/-/vite-builder-4.4.2.tgz",
+      "integrity": "sha512-fJaIwMA8ID6BU5EqmoDvnhq4qYDJeWjdHk4jfqy8D3Nm7CoUW0BvX7Ee92XoO05rtUiClGlk/NQ1Ii8hs3ZIbw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@nuxt/kit": "4.4.2",
+        "@rollup/plugin-replace": "^6.0.3",
+        "@vitejs/plugin-vue": "^6.0.4",
+        "@vitejs/plugin-vue-jsx": "^5.1.4",
+        "autoprefixer": "^10.4.27",
+        "consola": "^3.4.2",
+        "cssnano": "^7.1.3",
+        "defu": "^6.1.4",
+        "escape-string-regexp": "^5.0.0",
+        "exsolve": "^1.0.8",
+        "get-port-please": "^3.2.0",
+        "jiti": "^2.6.1",
+        "knitwork": "^1.3.0",
+        "magic-string": "^0.30.21",
+        "mlly": "^1.8.1",
+        "mocked-exports": "^0.1.1",
+        "nypm": "^0.6.5",
+        "pathe": "^2.0.3",
+        "pkg-types": "^2.3.0",
+        "postcss": "^8.5.8",
+        "seroval": "^1.5.1",
+        "std-env": "^4.0.0",
+        "ufo": "^1.6.3",
+        "unenv": "^2.0.0-rc.24",
+        "vite": "^7.3.1",
+        "vite-node": "^5.3.0",
+        "vite-plugin-checker": "^0.12.0",
+        "vue-bundle-renderer": "^2.2.0"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "peerDependencies": {
+        "@babel/plugin-proposal-decorators": "^7.25.0",
+        "@babel/plugin-syntax-jsx": "^7.25.0",
+        "nuxt": "4.4.2",
+        "rolldown": "^1.0.0-beta.38",
+        "rollup-plugin-visualizer": "^6.0.0 || ^7.0.1",
+        "vue": "^3.3.4"
+      },
+      "peerDependenciesMeta": {
+        "@babel/plugin-proposal-decorators": {
+          "optional": true
+        },
+        "@babel/plugin-syntax-jsx": {
+          "optional": true
+        },
+        "rolldown": {
+          "optional": true
+        },
+        "rollup-plugin-visualizer": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@oslojs/encoding": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz",
+      "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==",
+      "license": "MIT"
+    },
+    "node_modules/@oxc-minify/binding-android-arm-eabi": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-android-arm-eabi/-/binding-android-arm-eabi-0.117.0.tgz",
+      "integrity": "sha512-5Hf2KsGRjxp3HnPU/mse7cQJa5tWfMFUPZQcgSMVsv2JZnGFFOIDzA0Oja2KDD+VPJqMpEJKc2dCHAGZgJxsGg==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-android-arm64": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-android-arm64/-/binding-android-arm64-0.117.0.tgz",
+      "integrity": "sha512-uuxGwxA5J4Sap+gz4nxyM/rer6q2A4X1Oe8HpE0CZQyb5cSBULQ15btZiVG3xOBctI5O+c2dwR1aZAP4oGKcLw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-darwin-arm64": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-darwin-arm64/-/binding-darwin-arm64-0.117.0.tgz",
+      "integrity": "sha512-lLBf75cxUSLydumToKtGTwbLqO/1urScblJ33Vx0uF38M2ZbL2x51AybBV5vlfLjYNrxvQ8ov0Bj/OhsVO/biA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-darwin-x64": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-darwin-x64/-/binding-darwin-x64-0.117.0.tgz",
+      "integrity": "sha512-wBWwP1voLZMuN4hpe1HRtkPBd4/o/1qan5XssmmI/hewBvGHEHkyvVLS0zu+cKqXDxYzYvb/p+EqU+xSXhEl4A==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-freebsd-x64": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-freebsd-x64/-/binding-freebsd-x64-0.117.0.tgz",
+      "integrity": "sha512-pYSacHw698oH2vb70iP1cHk6x0zhvAuOvdskvNtEqvfziu8MSjKXa699vA9Cx72+DH5rwVuj1I3f+7no2fWglA==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-linux-arm-gnueabihf": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.117.0.tgz",
+      "integrity": "sha512-Ugm4Qj7F2+bccjhHCjjnSNHBDPyvjPXWrntID4WJpSrPqt+Az/o0EGdty9sWOjQXRZiTVpa80uqCWZQUn94yTA==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-linux-arm-musleabihf": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.117.0.tgz",
+      "integrity": "sha512-qrY6ZviO9wVRI/jl4nRZO4B9os8jaJQemMeWIyFInZNk3lhqihId8iBqMKibJnRaf+JRxLM9j68atXkFRhOHrg==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-linux-arm64-gnu": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.117.0.tgz",
+      "integrity": "sha512-2VLJHKEFBRhCihT/8uesuDPhXpbWu1OlHCxqQ7pdFVqKik1Maj5E9oSDcYzxqfaCRStvTHkmLVWJBK5CVcIadg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-linux-arm64-musl": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.117.0.tgz",
+      "integrity": "sha512-C3zapJconWpl2Y7LR3GkRkH6jxpuV2iVUfkFcHT5Ffn4Zu7l88mZa2dhcfdULZDybN1Phka/P34YUzuskUUrXw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-linux-ppc64-gnu": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.117.0.tgz",
+      "integrity": "sha512-2T/Bm+3/qTfuNS4gKSzL8qbiYk+ErHW2122CtDx+ilZAzvWcJ8IbqdZIbEWOlwwe03lESTxPwTBLFqVgQU2OeQ==",
+      "cpu": [
+        "ppc64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-linux-riscv64-gnu": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.117.0.tgz",
+      "integrity": "sha512-MKLjpldYkeoB4T+yAi4aIAb0waifxUjLcKkCUDmYAY3RqBJTvWK34KtfaKZL0IBMIXfD92CbKkcxQirDUS9Xcg==",
+      "cpu": [
+        "riscv64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-linux-riscv64-musl": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.117.0.tgz",
+      "integrity": "sha512-UFVcbPvKUStry6JffriobBp8BHtjmLLPl4bCY+JMxIn/Q3pykCpZzRwFTcDurG/kY8tm+uSNfKKdRNa5Nh9A7g==",
+      "cpu": [
+        "riscv64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-linux-s390x-gnu": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.117.0.tgz",
+      "integrity": "sha512-B9GyPQ1NKbvpETVAMyJMfRlD3c6UJ7kiuFUAlx9LTYiQL+YIyT6vpuRlq1zgsXxavZluVrfeJv6x0owV4KDx4Q==",
+      "cpu": [
+        "s390x"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-linux-x64-gnu": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.117.0.tgz",
+      "integrity": "sha512-fXfhtr+WWBGNy4M5GjAF5vu/lpulR4Me34FjTyaK9nDrTZs7LM595UDsP1wliksqp4hD/KdoqHGmbCrC+6d4vA==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-linux-x64-musl": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-x64-musl/-/binding-linux-x64-musl-0.117.0.tgz",
+      "integrity": "sha512-jFBgGbx1oLadb83ntJmy1dWlAHSQanXTS21G4PgkxyONmxZdZ/UMKr7KsADzMuoPsd2YhJHxzRpwJd9U+4BFBw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-openharmony-arm64": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-openharmony-arm64/-/binding-openharmony-arm64-0.117.0.tgz",
+      "integrity": "sha512-nxPd9vx1vYz8IlIMdl9HFdOK/ood1H5hzbSFsyO8JU55tkcJoBL8TLCbuFf9pHpOy27l2gcPyV6z3p4eAcTH5Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openharmony"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-wasm32-wasi": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-wasm32-wasi/-/binding-wasm32-wasi-0.117.0.tgz",
+      "integrity": "sha512-pSvjJ6cCCfEXSteWSiVfZhdRzvpmS3tLhlXrXTYiuTDFrkRCobRP39SRwAzK23rE9i/m2JAaES2xPEW6+xu85g==",
+      "cpu": [
+        "wasm32"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "@napi-rs/wasm-runtime": "^1.1.1"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-win32-arm64-msvc": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.117.0.tgz",
+      "integrity": "sha512-9NoT9baFrWPdJRIZVQ1jzPZW9TjPT2sbzQyDdoK7uD1V8JXCe1L2y7sp9k2ldZZheaIcmtNwHc7jyD7kYz/0XQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-win32-ia32-msvc": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.117.0.tgz",
+      "integrity": "sha512-E51LTjkRei5u2dpFiYSObuh+e43xg45qlmilSTd0XDGFdYJCOv62Q0MEn61TR+efQYPNleYwWdTS9t+tp9p/4w==",
+      "cpu": [
+        "ia32"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-minify/binding-win32-x64-msvc": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.117.0.tgz",
+      "integrity": "sha512-I8vniPOxWQdxfIbXNvQLaJ1n8SrnqES6wuiAX10CU72sKsizkds9kDaJ1KzWvDy39RKhTBmD1cJsU2uxPFgizQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-android-arm-eabi": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.117.0.tgz",
+      "integrity": "sha512-XarGPJpaobgKjfm7xRfCGWWszuPbm/OeP91NdMhxtcLZ/qLTmWF0P0z0gqmr0Uysi1F1v1BNtcST11THMrcEOw==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-android-arm64": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.117.0.tgz",
+      "integrity": "sha512-EPTs2EBijGmyhPso4rXAL0NSpECXER9IaVKFZEv83YcA6h4uhKW47kmYt+OZcSp130zhHx+lTWILDQ/LDkCRNA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-darwin-arm64": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.117.0.tgz",
+      "integrity": "sha512-3bAEpyih6r/Kb+Xzn1em1qBMClOS7NsVWgF86k95jpysR5ix/HlKFKSy7cax6PcS96HeHR4kjlME20n/XK1zNg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-darwin-x64": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.117.0.tgz",
+      "integrity": "sha512-W7S99zFwVZhSbCxvjfZkioStFU249DBc4TJw/kK6kfKwx2Zew+jvizX5Y3ZPkAh7fBVUSNOdSeOqLBHLiP50tw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-freebsd-x64": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.117.0.tgz",
+      "integrity": "sha512-xH76lqSdjCSY0KUMPwLXlvQ3YEm3FFVEQmgiOCGNf+stZ6E4Mo3nC102Bo8yKd7aW0foIPAFLYsHgj7vVI/axw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-linux-arm-gnueabihf": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.117.0.tgz",
+      "integrity": "sha512-9Hdm1imzrn4RdMYnQKKcy+7p7QsSPIrgVIZmpGSJT02nYDuBWLdG1pdYMPFoEo46yiXry3tS3RoHIpNbT1IiyQ==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-linux-arm-musleabihf": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.117.0.tgz",
+      "integrity": "sha512-Itszer/VCeYhYVJLcuKnHktlY8QyGnVxapltP68S1XRGlV6IsM9HQAElJRMwQhT6/GkMjOhANmkv2Qu/9v44lw==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-linux-arm64-gnu": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.117.0.tgz",
+      "integrity": "sha512-jBxD7DtlHQ36ivjjZdH0noQJgWNouenzpLmXNKnYaCsBfo3jY95m5iyjYQEiWkvkhJ3TJUAs7tQ1/kEpY7x/Kg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-linux-arm64-musl": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.117.0.tgz",
+      "integrity": "sha512-QagKTDF4lrz8bCXbUi39Uq5xs7C7itAseKm51f33U+Dyar9eJY/zGKqfME9mKLOiahX7Fc1J3xMWVS0AdDXLPg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-linux-ppc64-gnu": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.117.0.tgz",
+      "integrity": "sha512-RPddpcE/0xxWaommWy0c5i/JdrXcXAkxBS2GOrAUh5LKmyCh03hpJedOAWszG4ADsKQwoUQQ1/tZVGRhZIWtKA==",
+      "cpu": [
+        "ppc64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-linux-riscv64-gnu": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.117.0.tgz",
+      "integrity": "sha512-ur/WVZF9FSOiZGxyP+nfxZzuv6r5OJDYoVxJnUR7fM/hhXLh4V/be6rjbzm9KLCDBRwYCEKJtt+XXNccwd06IA==",
+      "cpu": [
+        "riscv64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-linux-riscv64-musl": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.117.0.tgz",
+      "integrity": "sha512-ujGcAx8xAMvhy7X5sBFi3GXML1EtyORuJZ5z2T6UV3U416WgDX/4OCi3GnoteeenvxIf6JgP45B+YTHpt71vpA==",
+      "cpu": [
+        "riscv64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-linux-s390x-gnu": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.117.0.tgz",
+      "integrity": "sha512-hbsfKjUwRjcMZZvvmpZSc+qS0bHcHRu8aV/I3Ikn9BzOA0ZAgUE7ctPtce5zCU7bM8dnTLi4sJ1Pi9YHdx6Urw==",
+      "cpu": [
+        "s390x"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-linux-x64-gnu": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.117.0.tgz",
+      "integrity": "sha512-1QrTrf8rige7UPJrYuDKJLQOuJlgkt+nRSJLBMHWNm9TdivzP48HaK3f4q18EjNlglKtn03lgjMu4fryDm8X4A==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-linux-x64-musl": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.117.0.tgz",
+      "integrity": "sha512-gRvK6HPzF5ITRL68fqb2WYYs/hGviPIbkV84HWCgiJX+LkaOpp+HIHQl3zVZdyKHwopXToTbXbtx/oFjDjl8pg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-openharmony-arm64": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.117.0.tgz",
+      "integrity": "sha512-QPJvFbnnDZZY7xc+xpbIBWLThcGBakwaYA9vKV8b3+oS5MGfAZUoTFJcix5+Zg2Ri46sOfrUim6Y6jsKNcssAQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openharmony"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-wasm32-wasi": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.117.0.tgz",
+      "integrity": "sha512-+XRSNA0xt3pk/6CUHM7pykVe7M8SdifJk8LX1+fIp/zefvR3HBieZCbwG5un8gogNgh7srLycoh/cQA9uozv5g==",
+      "cpu": [
+        "wasm32"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "@napi-rs/wasm-runtime": "^1.1.1"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-win32-arm64-msvc": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.117.0.tgz",
+      "integrity": "sha512-GpxeGS+Vo030DsrXeRPc7OSJOQIyAHkM3mzwBcnQjg/79XnOIDDMXJ5X6/aNdkVt/+Pv35pqKzGA4TQau97x8w==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-win32-ia32-msvc": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.117.0.tgz",
+      "integrity": "sha512-tchWEYiso1+objTZirmlR+w3fcIel6PVBOJ8NuC2Jr30dxBOiKUfFLovJLANwHg1+TzeD6pVSLIIIEf2T5o5lQ==",
+      "cpu": [
+        "ia32"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-parser/binding-win32-x64-msvc": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.117.0.tgz",
+      "integrity": "sha512-ysRJAjIbB4e5y+t9PZs7TwbgOV/GVT//s30AORLCT/pedYwpYzHq6ApXK7is9fvyfZtgT3anNir8+esurmyaDw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-project/types": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.117.0.tgz",
+      "integrity": "sha512-C/kPXBphID44fXdsa2xSOCuzX8fKZiFxPsvucJ6Yfkr6CJlMA+kNLPNKyLoI+l9XlDsNxBrz6h7IIjKU8pB69w==",
+      "license": "MIT",
+      "peer": true,
+      "funding": {
+        "url": "https://github.com/sponsors/Boshen"
+      }
+    },
+    "node_modules/@oxc-transform/binding-android-arm-eabi": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-android-arm-eabi/-/binding-android-arm-eabi-0.117.0.tgz",
+      "integrity": "sha512-17giX7h5VR9Eodru4OoSCFdgwLFIaUxeEn8JWe0vMZrAuRbT9NiDTy5dXdbGQBoO8aXPkbGS38FGlvbi31aujw==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-android-arm64": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-android-arm64/-/binding-android-arm64-0.117.0.tgz",
+      "integrity": "sha512-1LrDd1CPochtLx04pAafdah6QtOQQj0/Evttevi+0u8rCI5FKucIG7pqBHkIQi/y7pycFYIj+GebhET80maeUg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-darwin-arm64": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-arm64/-/binding-darwin-arm64-0.117.0.tgz",
+      "integrity": "sha512-K1Xo52xJOvFfHSkz2ax9X5Qsku23RCfTIPbHZWdUCAQ1TQooI+sFcewSubhVUJ4DVK12/tYT//XXboumin+FHA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-darwin-x64": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-x64/-/binding-darwin-x64-0.117.0.tgz",
+      "integrity": "sha512-ftFT/8Laolfq49mRRWLkIhd1AbJ0MI5bW3LwddvdoAg9zXwkx4qhzTYyBPRZhvXWftts+NjlHfHsXCOqI4tPtw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-freebsd-x64": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-freebsd-x64/-/binding-freebsd-x64-0.117.0.tgz",
+      "integrity": "sha512-QDRyw0atg9BMnwOwnJeW6REzWPLEjiWtsCc2Sj612F1hCdvP+n0L3o8sHinEWM+BiOkOYtUxHA69WjUslc3G+g==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-linux-arm-gnueabihf": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.117.0.tgz",
+      "integrity": "sha512-UvpvOjyQVgiIJahIpMT0qAsLJT8O1ibHTBgXGOsZkQgw1xmjARPQ07dpRcucPPn6cqCF3wrxfbqtr2vFHaMkdA==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-linux-arm-musleabihf": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.117.0.tgz",
+      "integrity": "sha512-cIhztGFjKk8ngP+/7EPkEhzWMGr2neezxgWirSn/f/MirjH234oHHGJ2diKIbGQEsy0aOuJMTkL9NLfzfmH51A==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-linux-arm64-gnu": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.117.0.tgz",
+      "integrity": "sha512-mXbDfvDN0RZVg7v4LohNzU0kK3fMAZgkUKTkpFVgxEvzibEG5VpSznkypUwHI4a8U8pz+K6mGaLetX3Xt+CvvA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-linux-arm64-musl": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.117.0.tgz",
+      "integrity": "sha512-ykxpPQp0eAcSmhy0Y3qKvdanHY4d8THPonDfmCoktUXb6r0X6qnjpJB3V+taN1wevW55bOEZd97kxtjTKjqhmg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-linux-ppc64-gnu": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.117.0.tgz",
+      "integrity": "sha512-Rvspti4Kr7eq6zSrURK5WjscfWQPvmy/KjJZV45neRKW8RLonE3r9+NgrwSLGoHvQ3F24fbqlkplox1RtlhH5A==",
+      "cpu": [
+        "ppc64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-linux-riscv64-gnu": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.117.0.tgz",
+      "integrity": "sha512-Dr2ZW9ZZ4l1eQ5JUEUY3smBh4JFPCPuybWaDZTLn3ADZjyd8ZtNXEjeMT8rQbbhbgSL9hEgbwaqraole3FNThQ==",
+      "cpu": [
+        "riscv64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-linux-riscv64-musl": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.117.0.tgz",
+      "integrity": "sha512-oD1Bnes1bIC3LVBSrWEoSUBj6fvatESPwAVWfJVGVQlqWuOs/ZBn1e4Nmbipo3KGPHK7DJY75r/j7CQCxhrOFQ==",
+      "cpu": [
+        "riscv64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-linux-s390x-gnu": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.117.0.tgz",
+      "integrity": "sha512-qT//IAPLvse844t99Kff5j055qEbXfwzWgvCMb0FyjisnB8foy25iHZxZIocNBe6qwrCYWUP1M8rNrB/WyfS1Q==",
+      "cpu": [
+        "s390x"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-linux-x64-gnu": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.117.0.tgz",
+      "integrity": "sha512-2YEO5X+KgNzFqRVO5dAkhjcI5gwxus4NSWVl/+cs2sI6P0MNPjqE3VWPawl4RTC11LvetiiZdHcujUCPM8aaUw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-linux-x64-musl": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-musl/-/binding-linux-x64-musl-0.117.0.tgz",
+      "integrity": "sha512-3wqWbTSaIFZvDr1aqmTul4cg8PRWYh6VC52E8bLI7ytgS/BwJLW+sDUU2YaGIds4sAf/1yKeJRmudRCDPW9INg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-openharmony-arm64": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-openharmony-arm64/-/binding-openharmony-arm64-0.117.0.tgz",
+      "integrity": "sha512-Ebxx6NPqhzlrjvx4+PdSqbOq+li0f7X59XtJljDghkbJsbnkHvhLmPR09ifHt5X32UlZN63ekjwcg/nbmHLLlA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openharmony"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-wasm32-wasi": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-wasm32-wasi/-/binding-wasm32-wasi-0.117.0.tgz",
+      "integrity": "sha512-Nn8mmcBiQ0XKHLTb05QBlH+CDkn7jf5YDVv9FtKhy4zJT0NEU9y3dXVbfcurOpsVrG9me4ktzDQNCaAoJjUQyw==",
+      "cpu": [
+        "wasm32"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "@napi-rs/wasm-runtime": "^1.1.1"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-win32-arm64-msvc": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.117.0.tgz",
+      "integrity": "sha512-15cbsF8diXWGnHrTsVgVeabETiT/KdMAfRAcot99xsaVecJs3pITNNjC6Qj+/TPNpehbgIFjlhhxOVSbQsTBgg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-win32-ia32-msvc": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.117.0.tgz",
+      "integrity": "sha512-I6DkhCuFX6p9rckdWiLuZfBWrrYUC7sNX+zLaCfa5zvrPNwo1/29KkefvqXVxu3AWT/6oZAbtc0A8/mqhETJPQ==",
+      "cpu": [
+        "ia32"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@oxc-transform/binding-win32-x64-msvc": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.117.0.tgz",
+      "integrity": "sha512-V7YzavQnYcRJBeJkp0qpb3FKrlm5I57XJetCYB4jsjStuboQmnFMZ/XQH55Szlf/kVyeU9ddQwv72gJJ5BrGjQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@pagefind/darwin-arm64": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.4.0.tgz",
+      "integrity": "sha512-2vMqkbv3lbx1Awea90gTaBsvpzgRs7MuSgKDxW0m9oV1GPZCZbZBJg/qL83GIUEN2BFlY46dtUZi54pwH+/pTQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@pagefind/darwin-x64": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.4.0.tgz",
+      "integrity": "sha512-e7JPIS6L9/cJfow+/IAqknsGqEPjJnVXGjpGm25bnq+NPdoD3c/7fAwr1OXkG4Ocjx6ZGSCijXEV4ryMcH2E3A==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@pagefind/default-ui": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/@pagefind/default-ui/-/default-ui-1.4.0.tgz",
+      "integrity": "sha512-wie82VWn3cnGEdIjh4YwNESyS1G6vRHwL6cNjy9CFgNnWW/PGRjsLq300xjVH5sfPFK3iK36UxvIBymtQIEiSQ==",
+      "license": "MIT"
+    },
+    "node_modules/@pagefind/freebsd-x64": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/@pagefind/freebsd-x64/-/freebsd-x64-1.4.0.tgz",
+      "integrity": "sha512-WcJVypXSZ+9HpiqZjFXMUobfFfZZ6NzIYtkhQ9eOhZrQpeY5uQFqNWLCk7w9RkMUwBv1HAMDW3YJQl/8OqsV0Q==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@pagefind/linux-arm64": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.4.0.tgz",
+      "integrity": "sha512-PIt8dkqt4W06KGmQjONw7EZbhDF+uXI7i0XtRLN1vjCUxM9vGPdtJc2mUyVPevjomrGz5M86M8bqTr6cgDp1Uw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@pagefind/linux-x64": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.4.0.tgz",
+      "integrity": "sha512-z4oddcWwQ0UHrTHR8psLnVlz6USGJ/eOlDPTDYZ4cI8TK8PgwRUPQZp9D2iJPNIPcS6Qx/E4TebjuGJOyK8Mmg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@pagefind/windows-x64": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.4.0.tgz",
+      "integrity": "sha512-NkT+YAdgS2FPCn8mIA9bQhiBs+xmniMGq1LFPDhcFn0+2yIUEiIG06t7bsZlhdjknEQRTSdT7YitP6fC5qwP0g==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@parcel/watcher": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz",
+      "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "detect-libc": "^2.0.3",
+        "is-glob": "^4.0.3",
+        "node-addon-api": "^7.0.0",
+        "picomatch": "^4.0.3"
+      },
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      },
+      "optionalDependencies": {
+        "@parcel/watcher-android-arm64": "2.5.6",
+        "@parcel/watcher-darwin-arm64": "2.5.6",
+        "@parcel/watcher-darwin-x64": "2.5.6",
+        "@parcel/watcher-freebsd-x64": "2.5.6",
+        "@parcel/watcher-linux-arm-glibc": "2.5.6",
+        "@parcel/watcher-linux-arm-musl": "2.5.6",
+        "@parcel/watcher-linux-arm64-glibc": "2.5.6",
+        "@parcel/watcher-linux-arm64-musl": "2.5.6",
+        "@parcel/watcher-linux-x64-glibc": "2.5.6",
+        "@parcel/watcher-linux-x64-musl": "2.5.6",
+        "@parcel/watcher-win32-arm64": "2.5.6",
+        "@parcel/watcher-win32-ia32": "2.5.6",
+        "@parcel/watcher-win32-x64": "2.5.6"
+      }
+    },
+    "node_modules/@parcel/watcher-android-arm64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz",
+      "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-darwin-arm64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz",
+      "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-darwin-x64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz",
+      "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-freebsd-x64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz",
+      "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm-glibc": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz",
+      "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm-musl": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz",
+      "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm64-glibc": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz",
+      "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm64-musl": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz",
+      "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-x64-glibc": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz",
+      "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-x64-musl": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz",
+      "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-wasm": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-wasm/-/watcher-wasm-2.5.6.tgz",
+      "integrity": "sha512-byAiBZ1t3tXQvc8dMD/eoyE7lTXYorhn+6uVW5AC+JGI1KtJC/LvDche5cfUE+qiefH+Ybq0bUCJU0aB1cSHUA==",
+      "bundleDependencies": [
+        "napi-wasm"
+      ],
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "is-glob": "^4.0.3",
+        "napi-wasm": "^1.1.0",
+        "picomatch": "^4.0.3"
+      },
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-wasm/node_modules/napi-wasm": {
+      "version": "1.1.0",
+      "inBundle": true,
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@parcel/watcher-win32-arm64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz",
+      "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-win32-ia32": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz",
+      "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==",
+      "cpu": [
+        "ia32"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-win32-x64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz",
+      "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@pkgjs/parseargs": {
+      "version": "0.11.0",
+      "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+      "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/@polka/url": {
+      "version": "1.0.0-next.29",
+      "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
+      "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@poppinss/colors": {
+      "version": "4.1.6",
+      "resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.6.tgz",
+      "integrity": "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "kleur": "^4.1.5"
+      }
+    },
+    "node_modules/@poppinss/dumper": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.7.0.tgz",
+      "integrity": "sha512-0UTYalzk2t6S4rA2uHOz5bSSW2CHdv4vggJI6Alg90yvl0UgXs6XSXpH96OH+bRkX4J/06djv29pqXJ0lq5Kag==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@poppinss/colors": "^4.1.5",
+        "@sindresorhus/is": "^7.0.2",
+        "supports-color": "^10.0.0"
+      }
+    },
+    "node_modules/@poppinss/exception": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.3.tgz",
+      "integrity": "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@radix-ui/primitive": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
+      "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
+      "license": "MIT"
+    },
+    "node_modules/@radix-ui/react-arrow": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
+      "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-primitive": "2.1.3"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-compose-refs": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
+      "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-context": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
+      "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-dismissable-layer": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz",
+      "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/primitive": "1.1.3",
+        "@radix-ui/react-compose-refs": "1.1.2",
+        "@radix-ui/react-primitive": "2.1.3",
+        "@radix-ui/react-use-callback-ref": "1.1.1",
+        "@radix-ui/react-use-escape-keydown": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-focus-guards": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz",
+      "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-focus-scope": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
+      "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.2",
+        "@radix-ui/react-primitive": "2.1.3",
+        "@radix-ui/react-use-callback-ref": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-id": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
+      "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-use-layout-effect": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-popover": {
+      "version": "1.1.15",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz",
+      "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/primitive": "1.1.3",
+        "@radix-ui/react-compose-refs": "1.1.2",
+        "@radix-ui/react-context": "1.1.2",
+        "@radix-ui/react-dismissable-layer": "1.1.11",
+        "@radix-ui/react-focus-guards": "1.1.3",
+        "@radix-ui/react-focus-scope": "1.1.7",
+        "@radix-ui/react-id": "1.1.1",
+        "@radix-ui/react-popper": "1.2.8",
+        "@radix-ui/react-portal": "1.1.9",
+        "@radix-ui/react-presence": "1.1.5",
+        "@radix-ui/react-primitive": "2.1.3",
+        "@radix-ui/react-slot": "1.2.3",
+        "@radix-ui/react-use-controllable-state": "1.2.2",
+        "aria-hidden": "^1.2.4",
+        "react-remove-scroll": "^2.6.3"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-popper": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
+      "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==",
+      "license": "MIT",
+      "dependencies": {
+        "@floating-ui/react-dom": "^2.0.0",
+        "@radix-ui/react-arrow": "1.1.7",
+        "@radix-ui/react-compose-refs": "1.1.2",
+        "@radix-ui/react-context": "1.1.2",
+        "@radix-ui/react-primitive": "2.1.3",
+        "@radix-ui/react-use-callback-ref": "1.1.1",
+        "@radix-ui/react-use-layout-effect": "1.1.1",
+        "@radix-ui/react-use-rect": "1.1.1",
+        "@radix-ui/react-use-size": "1.1.1",
+        "@radix-ui/rect": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-portal": {
+      "version": "1.1.9",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
+      "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-primitive": "2.1.3",
+        "@radix-ui/react-use-layout-effect": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-presence": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
+      "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.2",
+        "@radix-ui/react-use-layout-effect": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-primitive": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
+      "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-slot": "1.2.3"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-slot": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
+      "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.2"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-callback-ref": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
+      "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-controllable-state": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
+      "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-use-effect-event": "0.0.2",
+        "@radix-ui/react-use-layout-effect": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-effect-event": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
+      "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-use-layout-effect": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-escape-keydown": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
+      "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-use-callback-ref": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-layout-effect": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
+      "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-rect": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz",
+      "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/rect": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-size": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
+      "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-use-layout-effect": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/rect": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz",
+      "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
+      "license": "MIT"
+    },
+    "node_modules/@rolldown/pluginutils": {
+      "version": "1.0.0-rc.13",
+      "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.13.tgz",
+      "integrity": "sha512-3ngTAv6F/Py35BsYbeeLeecvhMKdsKm4AoOETVhAA+Qc8nrA2I0kF7oa93mE9qnIurngOSpMnQ0x2nQY2FPviA==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@rollup/plugin-alias": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-6.0.0.tgz",
+      "integrity": "sha512-tPCzJOtS7uuVZd+xPhoy5W4vThe6KWXNmsFCNktaAh5RTqcLiSfT4huPQIXkgJ6YCOjJHvecOAzQxLFhPxKr+g==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=20.19.0"
+      },
+      "peerDependencies": {
+        "rollup": ">=4.0.0"
+      },
+      "peerDependenciesMeta": {
+        "rollup": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@rollup/plugin-commonjs": {
+      "version": "29.0.2",
+      "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.2.tgz",
+      "integrity": "sha512-S/ggWH1LU7jTyi9DxZOKyxpVd4hF/OZ0JrEbeLjXk/DFXwRny0tjD2c992zOUYQobLrVkRVMDdmHP16HKP7GRg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@rollup/pluginutils": "^5.0.1",
+        "commondir": "^1.0.1",
+        "estree-walker": "^2.0.2",
+        "fdir": "^6.2.0",
+        "is-reference": "1.2.1",
+        "magic-string": "^0.30.3",
+        "picomatch": "^4.0.2"
+      },
+      "engines": {
+        "node": ">=16.0.0 || 14 >= 14.17"
+      },
+      "peerDependencies": {
+        "rollup": "^2.68.0||^3.0.0||^4.0.0"
+      },
+      "peerDependenciesMeta": {
+        "rollup": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@rollup/plugin-commonjs/node_modules/estree-walker": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@rollup/plugin-inject": {
+      "version": "5.0.5",
+      "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz",
+      "integrity": "sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@rollup/pluginutils": "^5.0.1",
+        "estree-walker": "^2.0.2",
+        "magic-string": "^0.30.3"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      },
+      "peerDependencies": {
+        "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+      },
+      "peerDependenciesMeta": {
+        "rollup": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@rollup/plugin-inject/node_modules/estree-walker": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@rollup/plugin-json": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz",
+      "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@rollup/pluginutils": "^5.1.0"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      },
+      "peerDependencies": {
+        "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+      },
+      "peerDependenciesMeta": {
+        "rollup": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@rollup/plugin-node-resolve": {
+      "version": "16.0.3",
+      "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz",
+      "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@rollup/pluginutils": "^5.0.1",
+        "@types/resolve": "1.20.2",
+        "deepmerge": "^4.2.2",
+        "is-module": "^1.0.0",
+        "resolve": "^1.22.1"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      },
+      "peerDependencies": {
+        "rollup": "^2.78.0||^3.0.0||^4.0.0"
+      },
+      "peerDependenciesMeta": {
+        "rollup": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@rollup/plugin-replace": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.3.tgz",
+      "integrity": "sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@rollup/pluginutils": "^5.0.1",
+        "magic-string": "^0.30.3"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      },
+      "peerDependencies": {
+        "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+      },
+      "peerDependenciesMeta": {
+        "rollup": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@rollup/plugin-terser": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-1.0.0.tgz",
+      "integrity": "sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "serialize-javascript": "^7.0.3",
+        "smob": "^1.0.0",
+        "terser": "^5.17.4"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      },
+      "peerDependencies": {
+        "rollup": "^2.0.0||^3.0.0||^4.0.0"
+      },
+      "peerDependenciesMeta": {
+        "rollup": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@rollup/pluginutils": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz",
+      "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0",
+        "estree-walker": "^2.0.2",
+        "picomatch": "^4.0.2"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      },
+      "peerDependencies": {
+        "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+      },
+      "peerDependenciesMeta": {
+        "rollup": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@rollup/pluginutils/node_modules/estree-walker": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+      "license": "MIT"
+    },
+    "node_modules/@rollup/rollup-android-arm-eabi": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.2.tgz",
+      "integrity": "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-android-arm64": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.2.tgz",
+      "integrity": "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-arm64": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.2.tgz",
+      "integrity": "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-x64": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.2.tgz",
+      "integrity": "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-freebsd-arm64": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.2.tgz",
+      "integrity": "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-freebsd-x64": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.2.tgz",
+      "integrity": "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.2.tgz",
+      "integrity": "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.2.tgz",
+      "integrity": "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-gnu": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.2.tgz",
+      "integrity": "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-musl": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.2.tgz",
+      "integrity": "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-loong64-gnu": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.2.tgz",
+      "integrity": "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==",
+      "cpu": [
+        "loong64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-loong64-musl": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.2.tgz",
+      "integrity": "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==",
+      "cpu": [
+        "loong64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.2.tgz",
+      "integrity": "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==",
+      "cpu": [
+        "ppc64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-ppc64-musl": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.2.tgz",
+      "integrity": "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==",
+      "cpu": [
+        "ppc64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.2.tgz",
+      "integrity": "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==",
+      "cpu": [
+        "riscv64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-riscv64-musl": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.2.tgz",
+      "integrity": "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==",
+      "cpu": [
+        "riscv64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-s390x-gnu": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.2.tgz",
+      "integrity": "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==",
+      "cpu": [
+        "s390x"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-x64-gnu": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz",
+      "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-x64-musl": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.2.tgz",
+      "integrity": "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-openbsd-x64": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.2.tgz",
+      "integrity": "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-openharmony-arm64": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.2.tgz",
+      "integrity": "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openharmony"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-arm64-msvc": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.2.tgz",
+      "integrity": "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-ia32-msvc": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.2.tgz",
+      "integrity": "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==",
+      "cpu": [
+        "ia32"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-x64-gnu": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.2.tgz",
+      "integrity": "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-x64-msvc": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.2.tgz",
+      "integrity": "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@shikijs/core": {
+      "version": "3.23.0",
+      "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.23.0.tgz",
+      "integrity": "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/types": "3.23.0",
+        "@shikijs/vscode-textmate": "^10.0.2",
+        "@types/hast": "^3.0.4",
+        "hast-util-to-html": "^9.0.5"
+      }
+    },
+    "node_modules/@shikijs/engine-javascript": {
+      "version": "3.23.0",
+      "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.23.0.tgz",
+      "integrity": "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/types": "3.23.0",
+        "@shikijs/vscode-textmate": "^10.0.2",
+        "oniguruma-to-es": "^4.3.4"
+      }
+    },
+    "node_modules/@shikijs/engine-oniguruma": {
+      "version": "3.23.0",
+      "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.23.0.tgz",
+      "integrity": "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/types": "3.23.0",
+        "@shikijs/vscode-textmate": "^10.0.2"
+      }
+    },
+    "node_modules/@shikijs/langs": {
+      "version": "3.23.0",
+      "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.23.0.tgz",
+      "integrity": "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/types": "3.23.0"
+      }
+    },
+    "node_modules/@shikijs/primitive": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.0.2.tgz",
+      "integrity": "sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/types": "4.0.2",
+        "@shikijs/vscode-textmate": "^10.0.2",
+        "@types/hast": "^3.0.4"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/@shikijs/primitive/node_modules/@shikijs/types": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz",
+      "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/vscode-textmate": "^10.0.2",
+        "@types/hast": "^3.0.4"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/@shikijs/themes": {
+      "version": "3.23.0",
+      "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.23.0.tgz",
+      "integrity": "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/types": "3.23.0"
+      }
+    },
+    "node_modules/@shikijs/types": {
+      "version": "3.23.0",
+      "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz",
+      "integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/vscode-textmate": "^10.0.2",
+        "@types/hast": "^3.0.4"
+      }
+    },
+    "node_modules/@shikijs/vscode-textmate": {
+      "version": "10.0.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz",
+      "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==",
+      "license": "MIT"
+    },
+    "node_modules/@simple-git/args-pathspec": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@simple-git/args-pathspec/-/args-pathspec-1.0.3.tgz",
+      "integrity": "sha512-ngJMaHlsWDTfjyq9F3VIQ8b7NXbBLq5j9i5bJ6XLYtD6qlDXT7fdKY2KscWWUF8t18xx052Y/PUO1K1TRc9yKA==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@simple-git/argv-parser": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@simple-git/argv-parser/-/argv-parser-1.1.1.tgz",
+      "integrity": "sha512-Q9lBcfQ+VQCpQqGJFHe5yooOS5hGdLFFbJ5R+R5aDsnkPCahtn1hSkMcORX65J2Z5lxSkD0lQorMsncuBQxYUw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@simple-git/args-pathspec": "^1.0.3"
+      }
+    },
+    "node_modules/@sindresorhus/is": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz",
+      "integrity": "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/is?sponsor=1"
+      }
+    },
+    "node_modules/@sindresorhus/merge-streams": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
+      "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@speed-highlight/core": {
+      "version": "1.2.15",
+      "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.15.tgz",
+      "integrity": "sha512-BMq1K3DsElxDWawkX6eLg9+CKJrTVGCBAWVuHXVUV2u0s2711qiChLSId6ikYPfxhdYocLNt3wWwSvDiTvFabw==",
+      "license": "CC0-1.0",
+      "peer": true
+    },
+    "node_modules/@tanstack/query-core": {
+      "version": "5.90.20",
+      "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.20.tgz",
+      "integrity": "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/tannerlinsley"
+      }
+    },
+    "node_modules/@tanstack/react-query": {
+      "version": "5.90.21",
+      "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.21.tgz",
+      "integrity": "sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==",
+      "license": "MIT",
+      "dependencies": {
+        "@tanstack/query-core": "5.90.20"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/tannerlinsley"
+      },
+      "peerDependencies": {
+        "react": "^18 || ^19"
+      }
+    },
+    "node_modules/@tybys/wasm-util": {
+      "version": "0.10.1",
+      "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
+      "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@types/babel__core": {
+      "version": "7.20.5",
+      "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+      "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.20.7",
+        "@babel/types": "^7.20.7",
+        "@types/babel__generator": "*",
+        "@types/babel__template": "*",
+        "@types/babel__traverse": "*"
+      }
+    },
+    "node_modules/@types/babel__generator": {
+      "version": "7.27.0",
+      "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+      "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "node_modules/@types/babel__template": {
+      "version": "7.4.4",
+      "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+      "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.1.0",
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "node_modules/@types/babel__traverse": {
+      "version": "7.28.0",
+      "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+      "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.28.2"
+      }
+    },
+    "node_modules/@types/braces": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/@types/braces/-/braces-3.0.5.tgz",
+      "integrity": "sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w==",
+      "license": "MIT"
+    },
+    "node_modules/@types/debug": {
+      "version": "4.1.12",
+      "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
+      "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/ms": "*"
+      }
+    },
+    "node_modules/@types/estree": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+      "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+      "license": "MIT"
+    },
+    "node_modules/@types/estree-jsx": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz",
+      "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "*"
+      }
+    },
+    "node_modules/@types/hast": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz",
+      "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "*"
+      }
+    },
+    "node_modules/@types/js-yaml": {
+      "version": "4.0.9",
+      "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
+      "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==",
+      "license": "MIT"
+    },
+    "node_modules/@types/mdast": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz",
+      "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "*"
+      }
+    },
+    "node_modules/@types/mdx": {
+      "version": "2.0.13",
+      "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz",
+      "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==",
+      "license": "MIT"
+    },
+    "node_modules/@types/micromatch": {
+      "version": "4.0.10",
+      "resolved": "https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.10.tgz",
+      "integrity": "sha512-5jOhFDElqr4DKTrTEbnW8DZ4Hz5LRUEmyrGpCMrD/NphYv3nUnaF08xmSLx1rGGnyEs/kFnhiw6dCgcDqMr5PQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/braces": "*"
+      }
+    },
+    "node_modules/@types/ms": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
+      "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
+      "license": "MIT"
+    },
+    "node_modules/@types/nlcst": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz",
+      "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "*"
+      }
+    },
+    "node_modules/@types/node": {
+      "version": "24.12.2",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.2.tgz",
+      "integrity": "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==",
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~7.16.0"
+      }
+    },
+    "node_modules/@types/react": {
+      "version": "19.2.14",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
+      "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "csstype": "^3.2.2"
+      }
+    },
+    "node_modules/@types/react-dom": {
+      "version": "19.2.3",
+      "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
+      "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
+      "license": "MIT",
+      "peer": true,
+      "peerDependencies": {
+        "@types/react": "^19.2.0"
+      }
+    },
+    "node_modules/@types/resolve": {
+      "version": "1.20.2",
+      "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
+      "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@types/sax": {
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz",
+      "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/unist": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
+      "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
+      "license": "MIT"
+    },
+    "node_modules/@ungap/structured-clone": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
+      "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
+      "license": "ISC"
+    },
+    "node_modules/@unhead/vue": {
+      "version": "2.1.13",
+      "resolved": "https://registry.npmjs.org/@unhead/vue/-/vue-2.1.13.tgz",
+      "integrity": "sha512-HYy0shaHRnLNW9r85gppO8IiGz0ONWVV3zGdlT8CQ0tbTwixznJCIiyqV4BSV1aIF1jJIye0pd1p/k6Eab8Z/A==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "hookable": "^6.0.1",
+        "unhead": "2.1.13"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/harlan-zw"
+      },
+      "peerDependencies": {
+        "vue": ">=3.5.18"
+      }
+    },
+    "node_modules/@vercel/analytics": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-2.0.0.tgz",
+      "integrity": "sha512-fP/ASXXz+1K/C2vWTnocd8RsGnkO9f1qOIDrhgQ3DagJtnea1EsM9AV9fDzjXlPIPb2vBQapxOIMCjtGIW8PZw==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@remix-run/react": "^2",
+        "@sveltejs/kit": "^1 || ^2",
+        "next": ">= 13",
+        "nuxt": ">= 3",
+        "react": "^18 || ^19 || ^19.0.0-rc",
+        "svelte": ">= 4",
+        "vue": "^3",
+        "vue-router": "^4"
+      },
+      "peerDependenciesMeta": {
+        "@remix-run/react": {
+          "optional": true
+        },
+        "@sveltejs/kit": {
+          "optional": true
+        },
+        "next": {
+          "optional": true
+        },
+        "react": {
+          "optional": true
+        },
+        "svelte": {
+          "optional": true
+        },
+        "vue": {
+          "optional": true
+        },
+        "vue-router": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@vercel/functions": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/@vercel/functions/-/functions-3.4.3.tgz",
+      "integrity": "sha512-kA14KIUVgAY6VXbhZ5jjY+s0883cV3cZqIU3WhrSRxuJ9KvxatMjtmzl0K23HK59oOUjYl7HaE/eYMmhmqpZzw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@vercel/oidc": "3.2.0"
+      },
+      "engines": {
+        "node": ">= 20"
+      },
+      "peerDependencies": {
+        "@aws-sdk/credential-provider-web-identity": "*"
+      },
+      "peerDependenciesMeta": {
+        "@aws-sdk/credential-provider-web-identity": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@vercel/nft": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-1.5.0.tgz",
+      "integrity": "sha512-IWTDeIoWhQ7ZtRO/JRKH+jhmeQvZYhtGPmzw/QGDY+wDCQqfm25P9yIdoAFagu4fWsK4IwZXDFIjrmp5rRm/sA==",
+      "license": "MIT",
+      "dependencies": {
+        "@mapbox/node-pre-gyp": "^2.0.0",
+        "@rollup/pluginutils": "^5.1.3",
+        "acorn": "^8.6.0",
+        "acorn-import-attributes": "^1.9.5",
+        "async-sema": "^3.1.1",
+        "bindings": "^1.4.0",
+        "estree-walker": "2.0.2",
+        "glob": "^13.0.0",
+        "graceful-fs": "^4.2.9",
+        "node-gyp-build": "^4.2.2",
+        "picomatch": "^4.0.2",
+        "resolve-from": "^5.0.0"
+      },
+      "bin": {
+        "nft": "out/cli.js"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/@vercel/nft/node_modules/balanced-match": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+      "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+      "license": "MIT",
+      "engines": {
+        "node": "18 || 20 || >=22"
+      }
+    },
+    "node_modules/@vercel/nft/node_modules/brace-expansion": {
+      "version": "5.0.5",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
+      "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^4.0.2"
+      },
+      "engines": {
+        "node": "18 || 20 || >=22"
+      }
+    },
+    "node_modules/@vercel/nft/node_modules/estree-walker": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+      "license": "MIT"
+    },
+    "node_modules/@vercel/nft/node_modules/glob": {
+      "version": "13.0.6",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
+      "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==",
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "minimatch": "^10.2.2",
+        "minipass": "^7.1.3",
+        "path-scurry": "^2.0.2"
+      },
+      "engines": {
+        "node": "18 || 20 || >=22"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@vercel/nft/node_modules/minimatch": {
+      "version": "10.2.5",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+      "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "brace-expansion": "^5.0.5"
+      },
+      "engines": {
+        "node": "18 || 20 || >=22"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@vercel/nft/node_modules/path-scurry": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
+      "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==",
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "lru-cache": "^11.0.0",
+        "minipass": "^7.1.2"
+      },
+      "engines": {
+        "node": "18 || 20 || >=22"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@vercel/oidc": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.2.0.tgz",
+      "integrity": "sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">= 20"
+      }
+    },
+    "node_modules/@vercel/routing-utils": {
+      "version": "5.3.3",
+      "resolved": "https://registry.npmjs.org/@vercel/routing-utils/-/routing-utils-5.3.3.tgz",
+      "integrity": "sha512-KYm2sLNUD48gDScv8ob4ejc3Gww2jcJyW80hTdYlenAPz/5BQar1Gyh38xrUuZ532TUwSb5mV1uRbAuiykq0EQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "path-to-regexp": "6.1.0",
+        "path-to-regexp-updated": "npm:path-to-regexp@6.3.0"
+      },
+      "optionalDependencies": {
+        "ajv": "^6.12.3"
+      }
+    },
+    "node_modules/@vercel/speed-insights": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@vercel/speed-insights/-/speed-insights-2.0.0.tgz",
+      "integrity": "sha512-jwkNcrTeafWxjmWq4AHBaptSqZiJkYU5adLC9QBSqeim0GcqDMgN5Ievh8OG1rJ6W3A4l1oiP7qr9CWxGuzu3w==",
+      "license": "Apache-2.0",
+      "peerDependencies": {
+        "@sveltejs/kit": "^1 || ^2",
+        "next": ">= 13",
+        "nuxt": ">= 3",
+        "react": "^18 || ^19 || ^19.0.0-rc",
+        "svelte": ">= 4",
+        "vue": "^3",
+        "vue-router": "^4"
+      },
+      "peerDependenciesMeta": {
+        "@sveltejs/kit": {
+          "optional": true
+        },
+        "next": {
+          "optional": true
+        },
+        "nuxt": {
+          "optional": true
+        },
+        "react": {
+          "optional": true
+        },
+        "svelte": {
+          "optional": true
+        },
+        "vue": {
+          "optional": true
+        },
+        "vue-router": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@vitejs/plugin-react": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz",
+      "integrity": "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/core": "^7.29.0",
+        "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+        "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+        "@rolldown/pluginutils": "1.0.0-rc.3",
+        "@types/babel__core": "^7.20.5",
+        "react-refresh": "^0.18.0"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "peerDependencies": {
+        "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/@vitejs/plugin-react/node_modules/@rolldown/pluginutils": {
+      "version": "1.0.0-rc.3",
+      "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz",
+      "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==",
+      "license": "MIT"
+    },
+    "node_modules/@vitejs/plugin-vue": {
+      "version": "6.0.6",
+      "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.6.tgz",
+      "integrity": "sha512-u9HHgfrq3AjXlysn0eINFnWQOJQLO9WN6VprZ8FXl7A2bYisv3Hui9Ij+7QZ41F/WYWarHjwBbXtD7dKg3uxbg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@rolldown/pluginutils": "1.0.0-rc.13"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "peerDependencies": {
+        "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
+        "vue": "^3.2.25"
+      }
+    },
+    "node_modules/@vitejs/plugin-vue-jsx": {
+      "version": "5.1.5",
+      "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-5.1.5.tgz",
+      "integrity": "sha512-jIAsvHOEtWpslLOI2MeElGFxH7M8pM83BU/Tor4RLyiwH0FM4nUW3xdvbw20EeU9wc5IspQwMq225K3CMnJEpA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/core": "^7.29.0",
+        "@babel/plugin-syntax-typescript": "^7.28.6",
+        "@babel/plugin-transform-typescript": "^7.28.6",
+        "@rolldown/pluginutils": "^1.0.0-rc.2",
+        "@vue/babel-plugin-jsx": "^2.0.1"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "peerDependencies": {
+        "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
+        "vue": "^3.0.0"
+      }
+    },
+    "node_modules/@volar/kit": {
+      "version": "2.4.28",
+      "resolved": "https://registry.npmjs.org/@volar/kit/-/kit-2.4.28.tgz",
+      "integrity": "sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@volar/language-service": "2.4.28",
+        "@volar/typescript": "2.4.28",
+        "typesafe-path": "^0.2.2",
+        "vscode-languageserver-textdocument": "^1.0.11",
+        "vscode-uri": "^3.0.8"
+      },
+      "peerDependencies": {
+        "typescript": "*"
+      }
+    },
+    "node_modules/@volar/language-core": {
+      "version": "2.4.28",
+      "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz",
+      "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@volar/source-map": "2.4.28"
+      }
+    },
+    "node_modules/@volar/language-server": {
+      "version": "2.4.28",
+      "resolved": "https://registry.npmjs.org/@volar/language-server/-/language-server-2.4.28.tgz",
+      "integrity": "sha512-NqcLnE5gERKuS4PUFwlhMxf6vqYo7hXtbMFbViXcbVkbZ905AIVWhnSo0ZNBC2V127H1/2zP7RvVOVnyITFfBw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@volar/language-core": "2.4.28",
+        "@volar/language-service": "2.4.28",
+        "@volar/typescript": "2.4.28",
+        "path-browserify": "^1.0.1",
+        "request-light": "^0.7.0",
+        "vscode-languageserver": "^9.0.1",
+        "vscode-languageserver-protocol": "^3.17.5",
+        "vscode-languageserver-textdocument": "^1.0.11",
+        "vscode-uri": "^3.0.8"
+      }
+    },
+    "node_modules/@volar/language-service": {
+      "version": "2.4.28",
+      "resolved": "https://registry.npmjs.org/@volar/language-service/-/language-service-2.4.28.tgz",
+      "integrity": "sha512-Rh/wYCZJrI5vCwMk9xyw/Z+MsWxlJY1rmMZPsxUoJKfzIRjS/NF1NmnuEcrMbEVGja00aVpCsInJfixQTMdvLw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@volar/language-core": "2.4.28",
+        "vscode-languageserver-protocol": "^3.17.5",
+        "vscode-languageserver-textdocument": "^1.0.11",
+        "vscode-uri": "^3.0.8"
+      }
+    },
+    "node_modules/@volar/source-map": {
+      "version": "2.4.28",
+      "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz",
+      "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@volar/typescript": {
+      "version": "2.4.28",
+      "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz",
+      "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@volar/language-core": "2.4.28",
+        "path-browserify": "^1.0.1",
+        "vscode-uri": "^3.0.8"
+      }
+    },
+    "node_modules/@vscode/emmet-helper": {
+      "version": "2.11.0",
+      "resolved": "https://registry.npmjs.org/@vscode/emmet-helper/-/emmet-helper-2.11.0.tgz",
+      "integrity": "sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "emmet": "^2.4.3",
+        "jsonc-parser": "^2.3.0",
+        "vscode-languageserver-textdocument": "^1.0.1",
+        "vscode-languageserver-types": "^3.15.1",
+        "vscode-uri": "^3.0.8"
+      }
+    },
+    "node_modules/@vscode/l10n": {
+      "version": "0.0.18",
+      "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.18.tgz",
+      "integrity": "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@vue-macros/common": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-3.1.2.tgz",
+      "integrity": "sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@vue/compiler-sfc": "^3.5.22",
+        "ast-kit": "^2.1.2",
+        "local-pkg": "^1.1.2",
+        "magic-string-ast": "^1.0.2",
+        "unplugin-utils": "^0.3.0"
+      },
+      "engines": {
+        "node": ">=20.19.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/vue-macros"
+      },
+      "peerDependencies": {
+        "vue": "^2.7.0 || ^3.2.25"
+      },
+      "peerDependenciesMeta": {
+        "vue": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@vue/babel-helper-vue-transform-on": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-2.0.1.tgz",
+      "integrity": "sha512-uZ66EaFbnnZSYqYEyplWvn46GhZ1KuYSThdT68p+am7MgBNbQ3hphTL9L+xSIsWkdktwhPYLwPgVWqo96jDdRA==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@vue/babel-plugin-jsx": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-2.0.1.tgz",
+      "integrity": "sha512-a8CaLQjD/s4PVdhrLD/zT574ZNPnZBOY+IhdtKWRB4HRZ0I2tXBi5ne7d9eCfaYwp5gU5+4KIyFTV1W1YL9xZA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.27.1",
+        "@babel/helper-plugin-utils": "^7.27.1",
+        "@babel/plugin-syntax-jsx": "^7.27.1",
+        "@babel/template": "^7.27.2",
+        "@babel/traverse": "^7.28.4",
+        "@babel/types": "^7.28.4",
+        "@vue/babel-helper-vue-transform-on": "2.0.1",
+        "@vue/babel-plugin-resolve-type": "2.0.1",
+        "@vue/shared": "^3.5.22"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      },
+      "peerDependenciesMeta": {
+        "@babel/core": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@vue/babel-plugin-resolve-type": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-2.0.1.tgz",
+      "integrity": "sha512-ybwgIuRGRRBhOU37GImDoWQoz+TlSqap65qVI6iwg/J7FfLTLmMf97TS7xQH9I7Qtr/gp161kYVdhr1ZMraSYQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.27.1",
+        "@babel/helper-module-imports": "^7.27.1",
+        "@babel/helper-plugin-utils": "^7.27.1",
+        "@babel/parser": "^7.28.4",
+        "@vue/compiler-sfc": "^3.5.22"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sxzz"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@vue/compiler-core": {
+      "version": "3.5.32",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.32.tgz",
+      "integrity": "sha512-4x74Tbtqnda8s/NSD6e1Dr5p1c8HdMU5RWSjMSUzb8RTcUQqevDCxVAitcLBKT+ie3o0Dl9crc/S/opJM7qBGQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/parser": "^7.29.2",
+        "@vue/shared": "3.5.32",
+        "entities": "^7.0.1",
+        "estree-walker": "^2.0.2",
+        "source-map-js": "^1.2.1"
+      }
+    },
+    "node_modules/@vue/compiler-core/node_modules/entities": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
+      "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
+      "license": "BSD-2-Clause",
+      "peer": true,
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/@vue/compiler-core/node_modules/estree-walker": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@vue/compiler-dom": {
+      "version": "3.5.32",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.32.tgz",
+      "integrity": "sha512-ybHAu70NtiEI1fvAUz3oXZqkUYEe5J98GjMDpTGl5iHb0T15wQYLR4wE3h9xfuTNA+Cm2f4czfe8B4s+CCH57Q==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@vue/compiler-core": "3.5.32",
+        "@vue/shared": "3.5.32"
+      }
+    },
+    "node_modules/@vue/compiler-sfc": {
+      "version": "3.5.32",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.32.tgz",
+      "integrity": "sha512-8UYUYo71cP/0YHMO814TRZlPuUUw3oifHuMR7Wp9SNoRSrxRQnhMLNlCeaODNn6kNTJsjFoQ/kqIj4qGvya4Xg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/parser": "^7.29.2",
+        "@vue/compiler-core": "3.5.32",
+        "@vue/compiler-dom": "3.5.32",
+        "@vue/compiler-ssr": "3.5.32",
+        "@vue/shared": "3.5.32",
+        "estree-walker": "^2.0.2",
+        "magic-string": "^0.30.21",
+        "postcss": "^8.5.8",
+        "source-map-js": "^1.2.1"
+      }
+    },
+    "node_modules/@vue/compiler-sfc/node_modules/estree-walker": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@vue/compiler-ssr": {
+      "version": "3.5.32",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.32.tgz",
+      "integrity": "sha512-Gp4gTs22T3DgRotZ8aA/6m2jMR+GMztvBXUBEUOYOcST+giyGWJ4WvFd7QLHBkzTxkfOt8IELKNdpzITLbA2rw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@vue/compiler-dom": "3.5.32",
+        "@vue/shared": "3.5.32"
+      }
+    },
+    "node_modules/@vue/devtools-api": {
+      "version": "6.6.4",
+      "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
+      "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
+      "license": "MIT",
+      "optional": true,
+      "peer": true
+    },
+    "node_modules/@vue/devtools-core": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-8.1.1.tgz",
+      "integrity": "sha512-bCCsSABp1/ot4j8xJEycM6Mtt2wbuucfByr6hMgjbYhrtlscOJypZKvy8f1FyWLYrLTchB5Qz216Lm92wfbq0A==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@vue/devtools-kit": "^8.1.1",
+        "@vue/devtools-shared": "^8.1.1"
+      },
+      "peerDependencies": {
+        "vue": "^3.0.0"
+      }
+    },
+    "node_modules/@vue/devtools-kit": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.1.1.tgz",
+      "integrity": "sha512-gVBaBv++i+adg4JpH71k9ppl4soyR7Y2McEqO5YNgv0BI1kMZ7BDX5gnwkZ5COYgiCyhejZG+yGNrBAjj6Coqg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@vue/devtools-shared": "^8.1.1",
+        "birpc": "^2.6.1",
+        "hookable": "^5.5.3",
+        "perfect-debounce": "^2.0.0"
+      }
+    },
+    "node_modules/@vue/devtools-kit/node_modules/birpc": {
+      "version": "2.9.0",
+      "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz",
+      "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==",
+      "license": "MIT",
+      "peer": true,
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/@vue/devtools-kit/node_modules/hookable": {
+      "version": "5.5.3",
+      "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
+      "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@vue/devtools-shared": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.1.1.tgz",
+      "integrity": "sha512-+h4ttmJYl/txpxHKaoZcaKpC+pvckgLzIDiSQlaQ7kKthKh8KuwoLW2D8hPJEnqKzXOvu15UHEoGyngAXCz0EQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@vue/reactivity": {
+      "version": "3.5.32",
+      "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.32.tgz",
+      "integrity": "sha512-/ORasxSGvZ6MN5gc+uE364SxFdJ0+WqVG0CENXaGW58TOCdrAW76WWaplDtECeS1qphvtBZtR+3/o1g1zL4xPQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@vue/shared": "3.5.32"
+      }
+    },
+    "node_modules/@vue/runtime-core": {
+      "version": "3.5.32",
+      "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.32.tgz",
+      "integrity": "sha512-pDrXCejn4UpFDFmMd27AcJEbHaLemaE5o4pbb7sLk79SRIhc6/t34BQA7SGNgYtbMnvbF/HHOftYBgFJtUoJUQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@vue/reactivity": "3.5.32",
+        "@vue/shared": "3.5.32"
+      }
+    },
+    "node_modules/@vue/runtime-dom": {
+      "version": "3.5.32",
+      "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.32.tgz",
+      "integrity": "sha512-1CDVv7tv/IV13V8Nip1k/aaObVbWqRlVCVezTwx3K07p7Vxossp5JU1dcPNhJk3w347gonIUT9jQOGutyJrSVQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@vue/reactivity": "3.5.32",
+        "@vue/runtime-core": "3.5.32",
+        "@vue/shared": "3.5.32",
+        "csstype": "^3.2.3"
+      }
+    },
+    "node_modules/@vue/server-renderer": {
+      "version": "3.5.32",
+      "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.32.tgz",
+      "integrity": "sha512-IOjm2+JQwRFS7W28HNuJeXQle9KdZbODFY7hFGVtnnghF51ta20EWAZJHX+zLGtsHhaU6uC9BGPV52KVpYryMQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@vue/compiler-ssr": "3.5.32",
+        "@vue/shared": "3.5.32"
+      },
+      "peerDependencies": {
+        "vue": "3.5.32"
+      }
+    },
+    "node_modules/@vue/shared": {
+      "version": "3.5.32",
+      "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.32.tgz",
+      "integrity": "sha512-ksNyrmRQzWJJ8n3cRDuSF7zNNontuJg1YHnmWRJd2AMu8Ij2bqwiiri2lH5rHtYPZjj4STkNcgcmiQqlOjiYGg==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/abbrev": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz",
+      "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==",
+      "license": "ISC",
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
+    "node_modules/abort-controller": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+      "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "event-target-shim": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=6.5"
+      }
+    },
+    "node_modules/acorn": {
+      "version": "8.16.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+      "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
+      "license": "MIT",
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-import-attributes": {
+      "version": "1.9.5",
+      "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
+      "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
+      "license": "MIT",
+      "peerDependencies": {
+        "acorn": "^8"
+      }
+    },
+    "node_modules/acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "license": "MIT",
+      "peerDependencies": {
+        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/agent-base": {
+      "version": "7.1.4",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
+      "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/ajv": {
+      "version": "6.14.0",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
+      "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
+      "license": "MIT",
+      "optional": true,
+      "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"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/ansi-regex": {
+      "version": "6.2.2",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+      "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "6.2.3",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+      "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/ansis": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.2.0.tgz",
+      "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==",
+      "license": "ISC",
+      "peer": true,
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+      "license": "ISC",
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/anymatch/node_modules/picomatch": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+      "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/archiver": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz",
+      "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==",
+      "license": "MIT",
+      "peer": true,
+      "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"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/archiver-utils": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz",
+      "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==",
+      "license": "MIT",
+      "peer": true,
+      "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"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/archiver-utils/node_modules/is-stream": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/arg": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
+      "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
+      "license": "MIT"
+    },
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "license": "Python-2.0"
+    },
+    "node_modules/aria-hidden": {
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
+      "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/aria-query": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
+      "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/array-iterate": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz",
+      "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/ast-kit": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.2.0.tgz",
+      "integrity": "sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/parser": "^7.28.5",
+        "pathe": "^2.0.3"
+      },
+      "engines": {
+        "node": ">=20.19.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sxzz"
+      }
+    },
+    "node_modules/ast-walker-scope": {
+      "version": "0.8.3",
+      "resolved": "https://registry.npmjs.org/ast-walker-scope/-/ast-walker-scope-0.8.3.tgz",
+      "integrity": "sha512-cbdCP0PGOBq0ASG+sjnKIoYkWMKhhz+F/h9pRexUdX2Hd38+WOlBkRKlqkGOSm0YQpcFMQBJeK4WspUAkwsEdg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/parser": "^7.28.4",
+        "ast-kit": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=20.19.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sxzz"
+      }
+    },
+    "node_modules/astring": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz",
+      "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==",
+      "license": "MIT",
+      "bin": {
+        "astring": "bin/astring"
+      }
+    },
+    "node_modules/astro": {
+      "version": "6.1.8",
+      "resolved": "https://registry.npmjs.org/astro/-/astro-6.1.8.tgz",
+      "integrity": "sha512-6fT9M12U3fpi13DiPavNKDIoBflASTSxmKTEe+zXhWtlebQuOqfOnIrMWyRmlXp+mgDsojmw+fVFG9LUTzKSog==",
+      "license": "MIT",
+      "dependencies": {
+        "@astrojs/compiler": "^3.0.1",
+        "@astrojs/internal-helpers": "0.8.0",
+        "@astrojs/markdown-remark": "7.1.0",
+        "@astrojs/telemetry": "3.3.1",
+        "@capsizecss/unpack": "^4.0.0",
+        "@clack/prompts": "^1.1.0",
+        "@oslojs/encoding": "^1.1.0",
+        "@rollup/pluginutils": "^5.3.0",
+        "aria-query": "^5.3.2",
+        "axobject-query": "^4.1.0",
+        "ci-info": "^4.4.0",
+        "clsx": "^2.1.1",
+        "common-ancestor-path": "^2.0.0",
+        "cookie": "^1.1.1",
+        "devalue": "^5.6.3",
+        "diff": "^8.0.3",
+        "dset": "^3.1.4",
+        "es-module-lexer": "^2.0.0",
+        "esbuild": "^0.27.3",
+        "flattie": "^1.1.1",
+        "fontace": "~0.4.1",
+        "github-slugger": "^2.0.0",
+        "html-escaper": "3.0.3",
+        "http-cache-semantics": "^4.2.0",
+        "js-yaml": "^4.1.1",
+        "magic-string": "^0.30.21",
+        "magicast": "^0.5.2",
+        "mrmime": "^2.0.1",
+        "neotraverse": "^0.6.18",
+        "obug": "^2.1.1",
+        "p-limit": "^7.3.0",
+        "p-queue": "^9.1.0",
+        "package-manager-detector": "^1.6.0",
+        "piccolore": "^0.1.3",
+        "picomatch": "^4.0.3",
+        "rehype": "^13.0.2",
+        "semver": "^7.7.4",
+        "shiki": "^4.0.2",
+        "smol-toml": "^1.6.0",
+        "svgo": "^4.0.1",
+        "tinyclip": "^0.1.12",
+        "tinyexec": "^1.0.4",
+        "tinyglobby": "^0.2.15",
+        "tsconfck": "^3.1.6",
+        "ultrahtml": "^1.6.0",
+        "unifont": "~0.7.4",
+        "unist-util-visit": "^5.1.0",
+        "unstorage": "^1.17.4",
+        "vfile": "^6.0.3",
+        "vite": "^7.3.1",
+        "vitefu": "^1.1.2",
+        "xxhash-wasm": "^1.1.0",
+        "yargs-parser": "^22.0.0",
+        "zod": "^4.3.6"
+      },
+      "bin": {
+        "astro": "bin/astro.mjs"
+      },
+      "engines": {
+        "node": ">=22.12.0",
+        "npm": ">=9.6.5",
+        "pnpm": ">=7.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/astrodotbuild"
+      },
+      "optionalDependencies": {
+        "sharp": "^0.34.0"
+      }
+    },
+    "node_modules/astro-expressive-code": {
+      "version": "0.41.7",
+      "resolved": "https://registry.npmjs.org/astro-expressive-code/-/astro-expressive-code-0.41.7.tgz",
+      "integrity": "sha512-hUpogGc6DdAd+I7pPXsctyYPRBJDK7Q7d06s4cyP0Vz3OcbziP3FNzN0jZci1BpCvLn9675DvS7B9ctKKX64JQ==",
+      "license": "MIT",
+      "dependencies": {
+        "rehype-expressive-code": "^0.41.7"
+      },
+      "peerDependencies": {
+        "astro": "^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta"
+      }
+    },
+    "node_modules/astro/node_modules/@shikijs/core": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.0.2.tgz",
+      "integrity": "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/primitive": "4.0.2",
+        "@shikijs/types": "4.0.2",
+        "@shikijs/vscode-textmate": "^10.0.2",
+        "@types/hast": "^3.0.4",
+        "hast-util-to-html": "^9.0.5"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/astro/node_modules/@shikijs/engine-javascript": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.0.2.tgz",
+      "integrity": "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/types": "4.0.2",
+        "@shikijs/vscode-textmate": "^10.0.2",
+        "oniguruma-to-es": "^4.3.4"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/astro/node_modules/@shikijs/engine-oniguruma": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.0.2.tgz",
+      "integrity": "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/types": "4.0.2",
+        "@shikijs/vscode-textmate": "^10.0.2"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/astro/node_modules/@shikijs/langs": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.0.2.tgz",
+      "integrity": "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/types": "4.0.2"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/astro/node_modules/@shikijs/themes": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.0.2.tgz",
+      "integrity": "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/types": "4.0.2"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/astro/node_modules/@shikijs/types": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz",
+      "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/vscode-textmate": "^10.0.2",
+        "@types/hast": "^3.0.4"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/astro/node_modules/shiki": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.0.2.tgz",
+      "integrity": "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/core": "4.0.2",
+        "@shikijs/engine-javascript": "4.0.2",
+        "@shikijs/engine-oniguruma": "4.0.2",
+        "@shikijs/langs": "4.0.2",
+        "@shikijs/themes": "4.0.2",
+        "@shikijs/types": "4.0.2",
+        "@shikijs/vscode-textmate": "^10.0.2",
+        "@types/hast": "^3.0.4"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/async": {
+      "version": "3.2.6",
+      "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
+      "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/async-sema": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/async-sema/-/async-sema-3.1.1.tgz",
+      "integrity": "sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==",
+      "license": "MIT"
+    },
+    "node_modules/autoprefixer": {
+      "version": "10.5.0",
+      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz",
+      "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "browserslist": "^4.28.2",
+        "caniuse-lite": "^1.0.30001787",
+        "fraction.js": "^5.3.4",
+        "picocolors": "^1.1.1",
+        "postcss-value-parser": "^4.2.0"
+      },
+      "bin": {
+        "autoprefixer": "bin/autoprefixer"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      },
+      "peerDependencies": {
+        "postcss": "^8.1.0"
+      }
+    },
+    "node_modules/axobject-query": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
+      "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/b4a": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz",
+      "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "peerDependencies": {
+        "react-native-b4a": "*"
+      },
+      "peerDependenciesMeta": {
+        "react-native-b4a": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/bail": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
+      "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/bare-events": {
+      "version": "2.8.2",
+      "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz",
+      "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "peerDependencies": {
+        "bare-abort-controller": "*"
+      },
+      "peerDependenciesMeta": {
+        "bare-abort-controller": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/bare-fs": {
+      "version": "4.7.1",
+      "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.1.tgz",
+      "integrity": "sha512-WDRsyVN52eAx/lBamKD6uyw8H4228h/x0sGGGegOamM2cd7Pag88GfMQalobXI+HaEUxpCkbKQUDOQqt9wawRw==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "dependencies": {
+        "bare-events": "^2.5.4",
+        "bare-path": "^3.0.0",
+        "bare-stream": "^2.6.4",
+        "bare-url": "^2.2.2",
+        "fast-fifo": "^1.3.2"
+      },
+      "engines": {
+        "bare": ">=1.16.0"
+      },
+      "peerDependencies": {
+        "bare-buffer": "*"
+      },
+      "peerDependenciesMeta": {
+        "bare-buffer": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/bare-os": {
+      "version": "3.8.7",
+      "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.8.7.tgz",
+      "integrity": "sha512-G4Gr1UsGeEy2qtDTZwL7JFLo2wapUarz7iTMcYcMFdS89AIQuBoyjgXZz0Utv7uHs3xA9LckhVbeBi8lEQrC+w==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "engines": {
+        "bare": ">=1.14.0"
+      }
+    },
+    "node_modules/bare-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz",
+      "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "dependencies": {
+        "bare-os": "^3.0.1"
+      }
+    },
+    "node_modules/bare-stream": {
+      "version": "2.13.0",
+      "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.0.tgz",
+      "integrity": "sha512-3zAJRZMDFGjdn+RVnNpF9kuELw+0Fl3lpndM4NcEOhb9zwtSo/deETfuIwMSE5BXanA0FrN1qVjffGwAg2Y7EA==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "dependencies": {
+        "streamx": "^2.25.0",
+        "teex": "^1.0.1"
+      },
+      "peerDependencies": {
+        "bare-abort-controller": "*",
+        "bare-buffer": "*",
+        "bare-events": "*"
+      },
+      "peerDependenciesMeta": {
+        "bare-abort-controller": {
+          "optional": true
+        },
+        "bare-buffer": {
+          "optional": true
+        },
+        "bare-events": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/bare-url": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.1.tgz",
+      "integrity": "sha512-fZapLWNB25gS+etK27NV9KgBNXgo2yeYHuj+OyPblQd6GYAE3JVy6aKxszMV5jhGGFwraXQKA5fldvf3lMyEqw==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "dependencies": {
+        "bare-path": "^3.0.0"
+      }
+    },
+    "node_modules/base64-js": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/baseline-browser-mapping": {
+      "version": "2.10.20",
+      "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.20.tgz",
+      "integrity": "sha512-1AaXxEPfXT+GvTBJFuy4yXVHWJBXa4OdbIebGN/wX5DlsIkU0+wzGnd2lOzokSk51d5LUmqjgBLRLlypLUqInQ==",
+      "license": "Apache-2.0",
+      "bin": {
+        "baseline-browser-mapping": "dist/cli.cjs"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/bcp-47": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/bcp-47/-/bcp-47-2.1.0.tgz",
+      "integrity": "sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w==",
+      "license": "MIT",
+      "dependencies": {
+        "is-alphabetical": "^2.0.0",
+        "is-alphanumerical": "^2.0.0",
+        "is-decimal": "^2.0.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/bcp-47-match": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-2.0.3.tgz",
+      "integrity": "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/bindings": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+      "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+      "license": "MIT",
+      "dependencies": {
+        "file-uri-to-path": "1.0.0"
+      }
+    },
+    "node_modules/birpc": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/birpc/-/birpc-4.0.0.tgz",
+      "integrity": "sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==",
+      "license": "MIT",
+      "peer": true,
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/boolbase": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+      "license": "ISC"
+    },
+    "node_modules/brace-expansion": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz",
+      "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+      "license": "MIT",
+      "dependencies": {
+        "fill-range": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/browserslist": {
+      "version": "4.28.2",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
+      "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "baseline-browser-mapping": "^2.10.12",
+        "caniuse-lite": "^1.0.30001782",
+        "electron-to-chromium": "^1.5.328",
+        "node-releases": "^2.0.36",
+        "update-browserslist-db": "^1.2.3"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/buffer": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.2.1"
+      }
+    },
+    "node_modules/buffer-crc32": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz",
+      "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/bundle-name": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz",
+      "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "run-applescript": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/c12": {
+      "version": "3.3.4",
+      "resolved": "https://registry.npmjs.org/c12/-/c12-3.3.4.tgz",
+      "integrity": "sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "chokidar": "^5.0.0",
+        "confbox": "^0.2.4",
+        "defu": "^6.1.6",
+        "dotenv": "^17.3.1",
+        "exsolve": "^1.0.8",
+        "giget": "^3.2.0",
+        "jiti": "^2.6.1",
+        "ohash": "^2.0.11",
+        "pathe": "^2.0.3",
+        "perfect-debounce": "^2.1.0",
+        "pkg-types": "^2.3.0",
+        "rc9": "^3.0.1"
+      },
+      "peerDependencies": {
+        "magicast": "*"
+      },
+      "peerDependenciesMeta": {
+        "magicast": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/cac": {
+      "version": "6.7.14",
+      "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
+      "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/caniuse-api": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
+      "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "browserslist": "^4.0.0",
+        "caniuse-lite": "^1.0.0",
+        "lodash.memoize": "^4.1.2",
+        "lodash.uniq": "^4.5.0"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001788",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz",
+      "integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "CC-BY-4.0"
+    },
+    "node_modules/ccount": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz",
+      "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/character-entities": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz",
+      "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/character-entities-html4": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz",
+      "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/character-entities-legacy": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz",
+      "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/character-reference-invalid": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz",
+      "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/chokidar": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
+      "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
+      "license": "MIT",
+      "dependencies": {
+        "readdirp": "^5.0.0"
+      },
+      "engines": {
+        "node": ">= 20.19.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/chownr": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+      "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/ci-info": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz",
+      "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/sibiraj-s"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/citty": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/citty/-/citty-0.2.2.tgz",
+      "integrity": "sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/cliui": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz",
+      "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==",
+      "license": "ISC",
+      "peer": true,
+      "dependencies": {
+        "string-width": "^7.2.0",
+        "strip-ansi": "^7.1.0",
+        "wrap-ansi": "^9.0.0"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/cliui/node_modules/emoji-regex": {
+      "version": "10.6.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
+      "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/cliui/node_modules/string-width": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+      "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "emoji-regex": "^10.3.0",
+        "get-east-asian-width": "^1.0.0",
+        "strip-ansi": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/cliui/node_modules/wrap-ansi": {
+      "version": "9.0.2",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz",
+      "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^6.2.1",
+        "string-width": "^7.0.0",
+        "strip-ansi": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/clsx": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+      "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/cluster-key-slot": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
+      "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/collapse-white-space": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz",
+      "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "license": "MIT"
+    },
+    "node_modules/comma-separated-tokens": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz",
+      "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/commander": {
+      "version": "13.1.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz",
+      "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==",
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/common-ancestor-path": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-2.0.0.tgz",
+      "integrity": "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==",
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": ">= 18"
+      }
+    },
+    "node_modules/commondir": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+      "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/compatx": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/compatx/-/compatx-0.2.0.tgz",
+      "integrity": "sha512-6gLRNt4ygsi5NyMVhceOCFv14CIdDFN7fQjX1U4+47qVE/+kjPoXMK65KWK+dWxmFzMTuKazoQ9sch6pM0p5oA==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/compress-commons": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz",
+      "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==",
+      "license": "MIT",
+      "peer": true,
+      "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"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/compress-commons/node_modules/is-stream": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/confbox": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz",
+      "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/consola": {
+      "version": "3.4.2",
+      "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz",
+      "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==",
+      "license": "MIT",
+      "engines": {
+        "node": "^14.18.0 || >=16.10.0"
+      }
+    },
+    "node_modules/convert-source-map": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+      "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+      "license": "MIT"
+    },
+    "node_modules/cookie": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
+      "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/cookie-es": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.3.tgz",
+      "integrity": "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==",
+      "license": "MIT"
+    },
+    "node_modules/core-util-is": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/crc-32": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
+      "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "bin": {
+        "crc32": "bin/crc32.njs"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/crc32-stream": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz",
+      "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "crc-32": "^1.2.0",
+        "readable-stream": "^4.0.0"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/croner": {
+      "version": "10.0.1",
+      "resolved": "https://registry.npmjs.org/croner/-/croner-10.0.1.tgz",
+      "integrity": "sha512-ixNtAJndqh173VQ4KodSdJEI6nuioBWI0V1ITNKhZZsO0pEMoDxz539T4FTTbSZ/xIOSuDnzxLVRqBVSvPNE2g==",
+      "funding": [
+        {
+          "type": "other",
+          "url": "https://paypal.me/hexagonpp"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/hexagon"
+        }
+      ],
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=18.0"
+      }
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/cross-spawn/node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "license": "ISC",
+      "peer": true
+    },
+    "node_modules/cross-spawn/node_modules/which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "license": "ISC",
+      "peer": true,
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/crossws": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz",
+      "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==",
+      "license": "MIT",
+      "dependencies": {
+        "uncrypto": "^0.1.3"
+      }
+    },
+    "node_modules/css-declaration-sorter": {
+      "version": "7.4.0",
+      "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.4.0.tgz",
+      "integrity": "sha512-LTuzjPoyA2vMGKKcaOqKSp7Ub2eGrNfKiZH4LpezxpNrsICGCSFvsQOI29psISxNZtaXibkC2CXzrQ5enMeGGw==",
+      "license": "ISC",
+      "peer": true,
+      "engines": {
+        "node": "^14 || ^16 || >=18"
+      },
+      "peerDependencies": {
+        "postcss": "^8.0.9"
+      }
+    },
+    "node_modules/css-select": {
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
+      "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "boolbase": "^1.0.0",
+        "css-what": "^6.1.0",
+        "domhandler": "^5.0.2",
+        "domutils": "^3.0.1",
+        "nth-check": "^2.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/css-selector-parser": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-3.3.0.tgz",
+      "integrity": "sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/mdevils"
+        },
+        {
+          "type": "patreon",
+          "url": "https://patreon.com/mdevils"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/css-tree": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz",
+      "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==",
+      "license": "MIT",
+      "dependencies": {
+        "mdn-data": "2.27.1",
+        "source-map-js": "^1.2.1"
+      },
+      "engines": {
+        "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
+      }
+    },
+    "node_modules/css-what": {
+      "version": "6.2.2",
+      "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
+      "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">= 6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/cssesc": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+      "license": "MIT",
+      "bin": {
+        "cssesc": "bin/cssesc"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/cssnano": {
+      "version": "7.1.7",
+      "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.1.7.tgz",
+      "integrity": "sha512-N5LGn/OlhMxDTvKACwUPMzT34SSj1b022pvUAE/Vh6r2WD1aUCbc+QNIP/JjX9VVxebdJWZQ3352Lt4oF7dQ/g==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "cssnano-preset-default": "^7.0.15",
+        "lilconfig": "^3.1.3"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/cssnano"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/cssnano-preset-default": {
+      "version": "7.0.15",
+      "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.15.tgz",
+      "integrity": "sha512-60kx7lJ40//HA85cIfQXSOJFby2D2V1pOMNHVCxue3KFWCjRzmiQyL9OvI+NAhwUlaojOfF9eK3nGvrJLCBUfQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "browserslist": "^4.28.2",
+        "css-declaration-sorter": "^7.2.0",
+        "cssnano-utils": "^5.0.2",
+        "postcss-calc": "^10.1.1",
+        "postcss-colormin": "^7.0.9",
+        "postcss-convert-values": "^7.0.11",
+        "postcss-discard-comments": "^7.0.7",
+        "postcss-discard-duplicates": "^7.0.3",
+        "postcss-discard-empty": "^7.0.2",
+        "postcss-discard-overridden": "^7.0.2",
+        "postcss-merge-longhand": "^7.0.6",
+        "postcss-merge-rules": "^7.0.10",
+        "postcss-minify-font-values": "^7.0.2",
+        "postcss-minify-gradients": "^7.0.4",
+        "postcss-minify-params": "^7.0.8",
+        "postcss-minify-selectors": "^7.1.0",
+        "postcss-normalize-charset": "^7.0.2",
+        "postcss-normalize-display-values": "^7.0.2",
+        "postcss-normalize-positions": "^7.0.3",
+        "postcss-normalize-repeat-style": "^7.0.3",
+        "postcss-normalize-string": "^7.0.2",
+        "postcss-normalize-timing-functions": "^7.0.2",
+        "postcss-normalize-unicode": "^7.0.8",
+        "postcss-normalize-url": "^7.0.2",
+        "postcss-normalize-whitespace": "^7.0.2",
+        "postcss-ordered-values": "^7.0.3",
+        "postcss-reduce-initial": "^7.0.8",
+        "postcss-reduce-transforms": "^7.0.2",
+        "postcss-svgo": "^7.1.2",
+        "postcss-unique-selectors": "^7.0.6"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/cssnano-utils": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-5.0.2.tgz",
+      "integrity": "sha512-kt41WLK7FLKfePzPi645Y+/NtW/nNM7Su6nlNUfJyRNW3JcuU3JU7+cWJc+JexTeZ8dRBvFufefdG2XpXkIo0A==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/csso": {
+      "version": "5.0.5",
+      "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz",
+      "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==",
+      "license": "MIT",
+      "dependencies": {
+        "css-tree": "~2.2.0"
+      },
+      "engines": {
+        "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0",
+        "npm": ">=7.0.0"
+      }
+    },
+    "node_modules/csso/node_modules/css-tree": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz",
+      "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==",
+      "license": "MIT",
+      "dependencies": {
+        "mdn-data": "2.0.28",
+        "source-map-js": "^1.0.1"
+      },
+      "engines": {
+        "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0",
+        "npm": ">=7.0.0"
+      }
+    },
+    "node_modules/csso/node_modules/mdn-data": {
+      "version": "2.0.28",
+      "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz",
+      "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==",
+      "license": "CC0-1.0"
+    },
+    "node_modules/cssom": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz",
+      "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==",
+      "license": "MIT"
+    },
+    "node_modules/csstype": {
+      "version": "3.2.3",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
+      "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/db0": {
+      "version": "0.3.4",
+      "resolved": "https://registry.npmjs.org/db0/-/db0-0.3.4.tgz",
+      "integrity": "sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw==",
+      "license": "MIT",
+      "peer": true,
+      "peerDependencies": {
+        "@electric-sql/pglite": "*",
+        "@libsql/client": "*",
+        "better-sqlite3": "*",
+        "drizzle-orm": "*",
+        "mysql2": "*",
+        "sqlite3": "*"
+      },
+      "peerDependenciesMeta": {
+        "@electric-sql/pglite": {
+          "optional": true
+        },
+        "@libsql/client": {
+          "optional": true
+        },
+        "better-sqlite3": {
+          "optional": true
+        },
+        "drizzle-orm": {
+          "optional": true
+        },
+        "mysql2": {
+          "optional": true
+        },
+        "sqlite3": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/decode-named-character-reference": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz",
+      "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==",
+      "license": "MIT",
+      "dependencies": {
+        "character-entities": "^2.0.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/deepmerge": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+      "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/default-browser": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz",
+      "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "bundle-name": "^4.1.0",
+        "default-browser-id": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/default-browser-id": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz",
+      "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/define-lazy-prop": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
+      "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/defu": {
+      "version": "6.1.7",
+      "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz",
+      "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==",
+      "license": "MIT"
+    },
+    "node_modules/denque": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
+      "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/depd": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/dequal": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
+      "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/destr": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz",
+      "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==",
+      "license": "MIT"
+    },
+    "node_modules/detect-libc": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+      "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/detect-node-es": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
+      "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
+      "license": "MIT"
+    },
+    "node_modules/devalue": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.7.1.tgz",
+      "integrity": "sha512-MUbZ586EgQqdRnC4yDrlod3BEdyvE4TapGYHMW2CiaW+KkkFmWEFqBUaLltEZCGi0iFXCEjRF0OjF0DV2QHjOA==",
+      "license": "MIT"
+    },
+    "node_modules/devlop": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
+      "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==",
+      "license": "MIT",
+      "dependencies": {
+        "dequal": "^2.0.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/diff": {
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz",
+      "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==",
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.3.1"
+      }
+    },
+    "node_modules/direction": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/direction/-/direction-2.0.1.tgz",
+      "integrity": "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==",
+      "license": "MIT",
+      "bin": {
+        "direction": "cli.js"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/dlv": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+      "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
+      "license": "MIT"
+    },
+    "node_modules/dom-serializer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+      "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+      "license": "MIT",
+      "dependencies": {
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.2",
+        "entities": "^4.2.0"
+      },
+      "funding": {
+        "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+      }
+    },
+    "node_modules/dom-serializer/node_modules/entities": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+      "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/domelementtype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
+        }
+      ],
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/domhandler": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+      "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "domelementtype": "^2.3.0"
+      },
+      "engines": {
+        "node": ">= 4"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/domhandler?sponsor=1"
+      }
+    },
+    "node_modules/domutils": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+      "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "dom-serializer": "^2.0.0",
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/domutils?sponsor=1"
+      }
+    },
+    "node_modules/dot-prop": {
+      "version": "10.1.0",
+      "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-10.1.0.tgz",
+      "integrity": "sha512-MVUtAugQMOff5RnBy2d9N31iG0lNwg1qAoAOn7pOK5wf94WIaE3My2p3uwTQuvS2AcqchkcR3bHByjaM0mmi7Q==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "type-fest": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/dotenv": {
+      "version": "17.4.2",
+      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz",
+      "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==",
+      "license": "BSD-2-Clause",
+      "peer": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://dotenvx.com"
+      }
+    },
+    "node_modules/dset": {
+      "version": "3.1.4",
+      "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz",
+      "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/duplexer": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
+      "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/eastasianwidth": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.5.340",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.340.tgz",
+      "integrity": "sha512-908qahOGocRMinT2nM3ajCEM99H4iPdv84eagPP3FfZy/1ZGeOy2CZYzjhms81ckOPCXPlW7LkY4XpxD8r1DrA==",
+      "license": "ISC"
+    },
+    "node_modules/emmet": {
+      "version": "2.4.11",
+      "resolved": "https://registry.npmjs.org/emmet/-/emmet-2.4.11.tgz",
+      "integrity": "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==",
+      "dev": true,
+      "license": "MIT",
+      "workspaces": [
+        "./packages/scanner",
+        "./packages/abbreviation",
+        "./packages/css-abbreviation",
+        "./"
+      ],
+      "dependencies": {
+        "@emmetio/abbreviation": "^2.3.3",
+        "@emmetio/css-abbreviation": "^2.1.8"
+      }
+    },
+    "node_modules/emoji-regex": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/encodeurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+      "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/entities": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
+      "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/error-stack-parser-es": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz",
+      "integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==",
+      "license": "MIT",
+      "peer": true,
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/errx": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/errx/-/errx-0.1.0.tgz",
+      "integrity": "sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/es-errors": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-module-lexer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz",
+      "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==",
+      "license": "MIT"
+    },
+    "node_modules/esast-util-from-estree": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz",
+      "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==",
+      "license": "MIT",
+      "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"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/esast-util-from-js": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz",
+      "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree-jsx": "^1.0.0",
+        "acorn": "^8.0.0",
+        "esast-util-from-estree": "^2.0.0",
+        "vfile-message": "^4.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/esbuild": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz",
+      "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "optionalDependencies": {
+        "@esbuild/aix-ppc64": "0.27.7",
+        "@esbuild/android-arm": "0.27.7",
+        "@esbuild/android-arm64": "0.27.7",
+        "@esbuild/android-x64": "0.27.7",
+        "@esbuild/darwin-arm64": "0.27.7",
+        "@esbuild/darwin-x64": "0.27.7",
+        "@esbuild/freebsd-arm64": "0.27.7",
+        "@esbuild/freebsd-x64": "0.27.7",
+        "@esbuild/linux-arm": "0.27.7",
+        "@esbuild/linux-arm64": "0.27.7",
+        "@esbuild/linux-ia32": "0.27.7",
+        "@esbuild/linux-loong64": "0.27.7",
+        "@esbuild/linux-mips64el": "0.27.7",
+        "@esbuild/linux-ppc64": "0.27.7",
+        "@esbuild/linux-riscv64": "0.27.7",
+        "@esbuild/linux-s390x": "0.27.7",
+        "@esbuild/linux-x64": "0.27.7",
+        "@esbuild/netbsd-arm64": "0.27.7",
+        "@esbuild/netbsd-x64": "0.27.7",
+        "@esbuild/openbsd-arm64": "0.27.7",
+        "@esbuild/openbsd-x64": "0.27.7",
+        "@esbuild/openharmony-arm64": "0.27.7",
+        "@esbuild/sunos-x64": "0.27.7",
+        "@esbuild/win32-arm64": "0.27.7",
+        "@esbuild/win32-ia32": "0.27.7",
+        "@esbuild/win32-x64": "0.27.7"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+      "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
+      "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/estree-util-attach-comments": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz",
+      "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/estree-util-build-jsx": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz",
+      "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree-jsx": "^1.0.0",
+        "devlop": "^1.0.0",
+        "estree-util-is-identifier-name": "^3.0.0",
+        "estree-walker": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/estree-util-is-identifier-name": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz",
+      "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==",
+      "license": "MIT",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/estree-util-scope": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz",
+      "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0",
+        "devlop": "^1.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/estree-util-to-js": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz",
+      "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree-jsx": "^1.0.0",
+        "astring": "^1.8.0",
+        "source-map": "^0.7.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/estree-util-visit": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz",
+      "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree-jsx": "^1.0.0",
+        "@types/unist": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/estree-walker": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+      "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0"
+      }
+    },
+    "node_modules/etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+      "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/event-target-shim": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+      "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/eventemitter3": {
+      "version": "5.0.4",
+      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz",
+      "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==",
+      "license": "MIT"
+    },
+    "node_modules/events": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+      "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=0.8.x"
+      }
+    },
+    "node_modules/events-universal": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
+      "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "dependencies": {
+        "bare-events": "^2.7.0"
+      }
+    },
+    "node_modules/execa": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
+      "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "cross-spawn": "^7.0.3",
+        "get-stream": "^8.0.1",
+        "human-signals": "^5.0.0",
+        "is-stream": "^3.0.0",
+        "merge-stream": "^2.0.0",
+        "npm-run-path": "^5.1.0",
+        "onetime": "^6.0.0",
+        "signal-exit": "^4.1.0",
+        "strip-final-newline": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=16.17"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/execa?sponsor=1"
+      }
+    },
+    "node_modules/expressive-code": {
+      "version": "0.41.7",
+      "resolved": "https://registry.npmjs.org/expressive-code/-/expressive-code-0.41.7.tgz",
+      "integrity": "sha512-2wZjC8OQ3TaVEMcBtYY4Va3lo6J+Ai9jf3d4dbhURMJcU4Pbqe6EcHe424MIZI0VHUA1bR6xdpoHYi3yxokWqA==",
+      "license": "MIT",
+      "dependencies": {
+        "@expressive-code/core": "^0.41.7",
+        "@expressive-code/plugin-frames": "^0.41.7",
+        "@expressive-code/plugin-shiki": "^0.41.7",
+        "@expressive-code/plugin-text-markers": "^0.41.7"
+      }
+    },
+    "node_modules/exsolve": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz",
+      "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+      "license": "MIT"
+    },
+    "node_modules/fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+      "license": "MIT"
+    },
+    "node_modules/fast-fifo": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
+      "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/fast-glob": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+      "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+      "license": "MIT",
+      "peer": true,
+      "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"
+      },
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
+    "node_modules/fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/fast-npm-meta": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/fast-npm-meta/-/fast-npm-meta-1.5.0.tgz",
+      "integrity": "sha512-71pTBPrA9WPPsJQ0Q06ZlTQQVJPYd87xZsvFwxFqru7a6kdriMVW1Hjd37W3W13ZuF/K/Zzq6eVlAHVoZCHuQw==",
+      "license": "MIT",
+      "peer": true,
+      "bin": {
+        "fast-npm-meta": "dist/cli.mjs"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/fast-uri": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
+      "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fastify"
+        },
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/fastify"
+        }
+      ],
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/fast-xml-builder": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.5.tgz",
+      "integrity": "sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/NaturalIntelligence"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "path-expression-matcher": "^1.1.3"
+      }
+    },
+    "node_modules/fast-xml-parser": {
+      "version": "5.7.2",
+      "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.7.2.tgz",
+      "integrity": "sha512-P7oW7tLbYnhOLQk/Gv7cZgzgMPP/XN03K02/Jy6Y/NHzyIAIpxuZIM/YqAkfiXFPxA2CTm7NtCijK9EDu09u2w==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/NaturalIntelligence"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@nodable/entities": "^2.1.0",
+        "fast-xml-builder": "^1.1.5",
+        "path-expression-matcher": "^1.5.0",
+        "strnum": "^2.2.3"
+      },
+      "bin": {
+        "fxparser": "src/cli/cli.js"
+      }
+    },
+    "node_modules/fastq": {
+      "version": "1.20.1",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
+      "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
+      "license": "ISC",
+      "peer": true,
+      "dependencies": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "node_modules/fdir": {
+      "version": "6.5.0",
+      "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+      "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "peerDependencies": {
+        "picomatch": "^3 || ^4"
+      },
+      "peerDependenciesMeta": {
+        "picomatch": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/file-uri-to-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+      "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+      "license": "MIT"
+    },
+    "node_modules/fill-range": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+      "license": "MIT",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/flattie": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz",
+      "integrity": "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/fontace": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/fontace/-/fontace-0.4.1.tgz",
+      "integrity": "sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==",
+      "license": "MIT",
+      "dependencies": {
+        "fontkitten": "^1.0.2"
+      }
+    },
+    "node_modules/fontkitten": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/fontkitten/-/fontkitten-1.0.3.tgz",
+      "integrity": "sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==",
+      "license": "MIT",
+      "dependencies": {
+        "tiny-inflate": "^1.0.3"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/foreground-child": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
+      "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
+      "license": "ISC",
+      "peer": true,
+      "dependencies": {
+        "cross-spawn": "^7.0.6",
+        "signal-exit": "^4.0.1"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/fraction.js": {
+      "version": "5.3.4",
+      "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz",
+      "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/rawify"
+      }
+    },
+    "node_modules/fresh": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+      "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+      "license": "MIT",
+      "peer": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/fuse.js": {
+      "version": "7.3.0",
+      "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.3.0.tgz",
+      "integrity": "sha512-plz8RVjfcDedTGfVngWH1jmJvBvAwi1v2jecfDerbEnMcmOYUEEwKFTHbNoCiYyzaK2Ws8lABkTCcRSqCY1q4w==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/krisk"
+      }
+    },
+    "node_modules/fzf": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/fzf/-/fzf-0.5.2.tgz",
+      "integrity": "sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q==",
+      "license": "BSD-3-Clause",
+      "peer": true
+    },
+    "node_modules/gensync": {
+      "version": "1.0.0-beta.2",
+      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "license": "ISC",
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
+    "node_modules/get-east-asian-width": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz",
+      "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/get-nonce": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
+      "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/get-port-please": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-3.2.0.tgz",
+      "integrity": "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/get-stream": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
+      "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/giget": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/giget/-/giget-3.2.0.tgz",
+      "integrity": "sha512-GvHTWcykIR/fP8cj8dMpuMMkvaeJfPvYnhq0oW+chSeIr+ldX21ifU2Ms6KBoyKZQZmVaUAAhQ2EZ68KJF8a7A==",
+      "license": "MIT",
+      "peer": true,
+      "bin": {
+        "giget": "dist/cli.mjs"
+      }
+    },
+    "node_modules/github-slugger": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz",
+      "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==",
+      "license": "ISC"
+    },
+    "node_modules/glob": {
+      "version": "10.5.0",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
+      "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
+      "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+      "license": "ISC",
+      "peer": true,
+      "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"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "license": "ISC",
+      "peer": true,
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/global-directory": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz",
+      "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "ini": "4.1.1"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/globby": {
+      "version": "16.2.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-16.2.0.tgz",
+      "integrity": "sha512-QrJia2qDf5BB/V6HYlDTs0I0lBahyjLzpGQg3KT7FnCdTonAyPy2RtY802m2k4ALx6Dp752f82WsOczEVr3l6Q==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@sindresorhus/merge-streams": "^4.0.0",
+        "fast-glob": "^3.3.3",
+        "ignore": "^7.0.5",
+        "is-path-inside": "^4.0.0",
+        "slash": "^5.1.0",
+        "unicorn-magic": "^0.4.0"
+      },
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+      "license": "ISC"
+    },
+    "node_modules/gzip-size": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-7.0.0.tgz",
+      "integrity": "sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "duplexer": "^0.1.2"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/h3": {
+      "version": "1.15.11",
+      "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.11.tgz",
+      "integrity": "sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==",
+      "license": "MIT",
+      "dependencies": {
+        "cookie-es": "^1.2.3",
+        "crossws": "^0.3.5",
+        "defu": "^6.1.6",
+        "destr": "^2.0.5",
+        "iron-webcrypto": "^1.2.1",
+        "node-mock-http": "^1.0.4",
+        "radix3": "^1.1.2",
+        "ufo": "^1.6.3",
+        "uncrypto": "^0.1.3"
+      }
+    },
+    "node_modules/hasown": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz",
+      "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/hast-util-embedded": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/hast-util-embedded/-/hast-util-embedded-3.0.0.tgz",
+      "integrity": "sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "hast-util-is-element": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-format": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/hast-util-format/-/hast-util-format-1.1.0.tgz",
+      "integrity": "sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "hast-util-embedded": "^3.0.0",
+        "hast-util-minify-whitespace": "^1.0.0",
+        "hast-util-phrasing": "^3.0.0",
+        "hast-util-whitespace": "^3.0.0",
+        "html-whitespace-sensitive-tag-names": "^3.0.0",
+        "unist-util-visit-parents": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-from-html": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz",
+      "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "devlop": "^1.1.0",
+        "hast-util-from-parse5": "^8.0.0",
+        "parse5": "^7.0.0",
+        "vfile": "^6.0.0",
+        "vfile-message": "^4.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-from-parse5": {
+      "version": "8.0.3",
+      "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz",
+      "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "@types/unist": "^3.0.0",
+        "devlop": "^1.0.0",
+        "hastscript": "^9.0.0",
+        "property-information": "^7.0.0",
+        "vfile": "^6.0.0",
+        "vfile-location": "^5.0.0",
+        "web-namespaces": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-has-property": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-3.0.0.tgz",
+      "integrity": "sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-is-body-ok-link": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/hast-util-is-body-ok-link/-/hast-util-is-body-ok-link-3.0.1.tgz",
+      "integrity": "sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-is-element": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz",
+      "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-minify-whitespace": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/hast-util-minify-whitespace/-/hast-util-minify-whitespace-1.0.1.tgz",
+      "integrity": "sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "hast-util-embedded": "^3.0.0",
+        "hast-util-is-element": "^3.0.0",
+        "hast-util-whitespace": "^3.0.0",
+        "unist-util-is": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-parse-selector": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz",
+      "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-phrasing": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/hast-util-phrasing/-/hast-util-phrasing-3.0.1.tgz",
+      "integrity": "sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "hast-util-embedded": "^3.0.0",
+        "hast-util-has-property": "^3.0.0",
+        "hast-util-is-body-ok-link": "^3.0.0",
+        "hast-util-is-element": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-raw": {
+      "version": "9.1.0",
+      "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz",
+      "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "@types/unist": "^3.0.0",
+        "@ungap/structured-clone": "^1.0.0",
+        "hast-util-from-parse5": "^8.0.0",
+        "hast-util-to-parse5": "^8.0.0",
+        "html-void-elements": "^3.0.0",
+        "mdast-util-to-hast": "^13.0.0",
+        "parse5": "^7.0.0",
+        "unist-util-position": "^5.0.0",
+        "unist-util-visit": "^5.0.0",
+        "vfile": "^6.0.0",
+        "web-namespaces": "^2.0.0",
+        "zwitch": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-select": {
+      "version": "6.0.4",
+      "resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-6.0.4.tgz",
+      "integrity": "sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "@types/unist": "^3.0.0",
+        "bcp-47-match": "^2.0.0",
+        "comma-separated-tokens": "^2.0.0",
+        "css-selector-parser": "^3.0.0",
+        "devlop": "^1.0.0",
+        "direction": "^2.0.0",
+        "hast-util-has-property": "^3.0.0",
+        "hast-util-to-string": "^3.0.0",
+        "hast-util-whitespace": "^3.0.0",
+        "nth-check": "^2.0.0",
+        "property-information": "^7.0.0",
+        "space-separated-tokens": "^2.0.0",
+        "unist-util-visit": "^5.0.0",
+        "zwitch": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-to-estree": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz",
+      "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0",
+        "@types/estree-jsx": "^1.0.0",
+        "@types/hast": "^3.0.0",
+        "comma-separated-tokens": "^2.0.0",
+        "devlop": "^1.0.0",
+        "estree-util-attach-comments": "^3.0.0",
+        "estree-util-is-identifier-name": "^3.0.0",
+        "hast-util-whitespace": "^3.0.0",
+        "mdast-util-mdx-expression": "^2.0.0",
+        "mdast-util-mdx-jsx": "^3.0.0",
+        "mdast-util-mdxjs-esm": "^2.0.0",
+        "property-information": "^7.0.0",
+        "space-separated-tokens": "^2.0.0",
+        "style-to-js": "^1.0.0",
+        "unist-util-position": "^5.0.0",
+        "zwitch": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-to-html": {
+      "version": "9.0.5",
+      "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz",
+      "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "@types/unist": "^3.0.0",
+        "ccount": "^2.0.0",
+        "comma-separated-tokens": "^2.0.0",
+        "hast-util-whitespace": "^3.0.0",
+        "html-void-elements": "^3.0.0",
+        "mdast-util-to-hast": "^13.0.0",
+        "property-information": "^7.0.0",
+        "space-separated-tokens": "^2.0.0",
+        "stringify-entities": "^4.0.0",
+        "zwitch": "^2.0.4"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-to-jsx-runtime": {
+      "version": "2.3.6",
+      "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz",
+      "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0",
+        "@types/hast": "^3.0.0",
+        "@types/unist": "^3.0.0",
+        "comma-separated-tokens": "^2.0.0",
+        "devlop": "^1.0.0",
+        "estree-util-is-identifier-name": "^3.0.0",
+        "hast-util-whitespace": "^3.0.0",
+        "mdast-util-mdx-expression": "^2.0.0",
+        "mdast-util-mdx-jsx": "^3.0.0",
+        "mdast-util-mdxjs-esm": "^2.0.0",
+        "property-information": "^7.0.0",
+        "space-separated-tokens": "^2.0.0",
+        "style-to-js": "^1.0.0",
+        "unist-util-position": "^5.0.0",
+        "vfile-message": "^4.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-to-mdast": {
+      "version": "10.1.2",
+      "resolved": "https://registry.npmjs.org/hast-util-to-mdast/-/hast-util-to-mdast-10.1.2.tgz",
+      "integrity": "sha512-FiCRI7NmOvM4y+f5w32jPRzcxDIz+PUqDwEqn1A+1q2cdp3B8Gx7aVrXORdOKjMNDQsD1ogOr896+0jJHW1EFQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "@types/mdast": "^4.0.0",
+        "@ungap/structured-clone": "^1.0.0",
+        "hast-util-phrasing": "^3.0.0",
+        "hast-util-to-html": "^9.0.0",
+        "hast-util-to-text": "^4.0.0",
+        "hast-util-whitespace": "^3.0.0",
+        "mdast-util-phrasing": "^4.0.0",
+        "mdast-util-to-hast": "^13.0.0",
+        "mdast-util-to-string": "^4.0.0",
+        "rehype-minify-whitespace": "^6.0.0",
+        "trim-trailing-lines": "^2.0.0",
+        "unist-util-position": "^5.0.0",
+        "unist-util-visit": "^5.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-to-parse5": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.1.tgz",
+      "integrity": "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "comma-separated-tokens": "^2.0.0",
+        "devlop": "^1.0.0",
+        "property-information": "^7.0.0",
+        "space-separated-tokens": "^2.0.0",
+        "web-namespaces": "^2.0.0",
+        "zwitch": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-to-string": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz",
+      "integrity": "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-to-text": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz",
+      "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "@types/unist": "^3.0.0",
+        "hast-util-is-element": "^3.0.0",
+        "unist-util-find-after": "^5.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hast-util-whitespace": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz",
+      "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hastscript": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz",
+      "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "comma-separated-tokens": "^2.0.0",
+        "hast-util-parse-selector": "^4.0.0",
+        "property-information": "^7.0.0",
+        "space-separated-tokens": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/hookable": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/hookable/-/hookable-6.1.1.tgz",
+      "integrity": "sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/html-escaper": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz",
+      "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==",
+      "license": "MIT"
+    },
+    "node_modules/html-url-attributes": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz",
+      "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==",
+      "license": "MIT",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/html-void-elements": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz",
+      "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/html-whitespace-sensitive-tag-names": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/html-whitespace-sensitive-tag-names/-/html-whitespace-sensitive-tag-names-3.0.1.tgz",
+      "integrity": "sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA==",
+      "license": "MIT",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/htmlparser2": {
+      "version": "10.1.0",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz",
+      "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==",
+      "funding": [
+        "https://github.com/fb55/htmlparser2?sponsor=1",
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.3",
+        "domutils": "^3.2.2",
+        "entities": "^7.0.1"
+      }
+    },
+    "node_modules/htmlparser2/node_modules/entities": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
+      "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/http-cache-semantics": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
+      "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==",
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/http-errors": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
+      "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "depd": "~2.0.0",
+        "inherits": "~2.0.4",
+        "setprototypeof": "~1.2.0",
+        "statuses": "~2.0.2",
+        "toidentifier": "~1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/http-shutdown": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/http-shutdown/-/http-shutdown-1.2.2.tgz",
+      "integrity": "sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "iojs": ">= 1.0.0",
+        "node": ">= 0.12.0"
+      }
+    },
+    "node_modules/https-proxy-agent": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+      "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+      "license": "MIT",
+      "dependencies": {
+        "agent-base": "^7.1.2",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/httpxy": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/httpxy/-/httpxy-0.5.0.tgz",
+      "integrity": "sha512-qwX7QX/rK2visT10/b7bSeZWQOMlSm3svTD0pZpU+vJjNUP0YHtNv4c3z+MO+MSnGuRFWJFdCZiV+7F7dXIOzg==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/human-signals": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
+      "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "engines": {
+        "node": ">=16.17.0"
+      }
+    },
+    "node_modules/i18next": {
+      "version": "23.16.8",
+      "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.16.8.tgz",
+      "integrity": "sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://locize.com"
+        },
+        {
+          "type": "individual",
+          "url": "https://locize.com/i18next.html"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.23.2"
+      }
+    },
+    "node_modules/ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "BSD-3-Clause",
+      "peer": true
+    },
+    "node_modules/ignore": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
+      "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/image-meta": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/image-meta/-/image-meta-0.2.2.tgz",
+      "integrity": "sha512-3MOLanc3sb3LNGWQl1RlQlNWURE5g32aUphrDyFeCsxBTk08iE3VNe4CwsUZ0Qs1X+EfX0+r29Sxdpza4B+yRA==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/impound": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/impound/-/impound-1.1.5.tgz",
+      "integrity": "sha512-5AUn+QE0UofqNHu5f2Skf6Svukdg4ehOIq8O0EtqIx4jta0CDZYBPqpIHt0zrlUTiFVYlLpeH39DoikXBjPKpA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@jridgewell/trace-mapping": "^0.3.31",
+        "es-module-lexer": "^2.0.0",
+        "pathe": "^2.0.3",
+        "unplugin": "^3.0.0",
+        "unplugin-utils": "^0.3.1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "license": "ISC",
+      "peer": true
+    },
+    "node_modules/ini": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz",
+      "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==",
+      "license": "ISC",
+      "peer": true,
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/inline-style-parser": {
+      "version": "0.2.7",
+      "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz",
+      "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==",
+      "license": "MIT"
+    },
+    "node_modules/ioredis": {
+      "version": "5.10.1",
+      "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.10.1.tgz",
+      "integrity": "sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@ioredis/commands": "1.5.1",
+        "cluster-key-slot": "^1.1.0",
+        "debug": "^4.3.4",
+        "denque": "^2.1.0",
+        "lodash.defaults": "^4.2.0",
+        "lodash.isarguments": "^3.1.0",
+        "redis-errors": "^1.2.0",
+        "redis-parser": "^3.0.0",
+        "standard-as-callback": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=12.22.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/ioredis"
+      }
+    },
+    "node_modules/iron-webcrypto": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz",
+      "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==",
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/brc-dd"
+      }
+    },
+    "node_modules/is-alphabetical": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
+      "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/is-alphanumerical": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz",
+      "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==",
+      "license": "MIT",
+      "dependencies": {
+        "is-alphabetical": "^2.0.0",
+        "is-decimal": "^2.0.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/is-core-module": {
+      "version": "2.16.1",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
+      "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "hasown": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-decimal": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
+      "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/is-docker": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+      "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
+      "license": "MIT",
+      "bin": {
+        "is-docker": "cli.js"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-hexadecimal": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz",
+      "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/is-in-ssh": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz",
+      "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-inside-container": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
+      "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
+      "license": "MIT",
+      "dependencies": {
+        "is-docker": "^3.0.0"
+      },
+      "bin": {
+        "is-inside-container": "cli.js"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-installed-globally": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-1.0.0.tgz",
+      "integrity": "sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "global-directory": "^4.0.1",
+        "is-path-inside": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-module": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
+      "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/is-path-inside": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz",
+      "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-plain-obj": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
+      "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-reference": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
+      "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@types/estree": "*"
+      }
+    },
+    "node_modules/is-stream": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
+      "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-wsl": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz",
+      "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==",
+      "license": "MIT",
+      "dependencies": {
+        "is-inside-container": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/isexe": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz",
+      "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==",
+      "license": "BlueOak-1.0.0",
+      "peer": true,
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/jackspeak": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+      "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+      "license": "BlueOak-1.0.0",
+      "peer": true,
+      "dependencies": {
+        "@isaacs/cliui": "^8.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      },
+      "optionalDependencies": {
+        "@pkgjs/parseargs": "^0.11.0"
+      }
+    },
+    "node_modules/jiti": {
+      "version": "2.6.1",
+      "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
+      "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
+      "license": "MIT",
+      "peer": true,
+      "bin": {
+        "jiti": "lib/jiti-cli.mjs"
+      }
+    },
+    "node_modules/js-cookie": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
+      "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "license": "MIT"
+    },
+    "node_modules/js-yaml": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+      "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^2.0.1"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/jsesc": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+      "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+      "license": "MIT",
+      "bin": {
+        "jsesc": "bin/jsesc"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/json5": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+      "license": "MIT",
+      "bin": {
+        "json5": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/jsonc-parser": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.1.tgz",
+      "integrity": "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/keymatch": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/keymatch/-/keymatch-1.0.5.tgz",
+      "integrity": "sha512-QBoXs/fUlNgdHBEnIyWUTeI7p+ooY6Ul8JAJ8pGVfEYUvVZJO6yj67zOau2DYiQbPznskpymks2TLY6nOwHwzg==",
+      "license": "MIT"
+    },
+    "node_modules/kleur": {
+      "version": "4.1.5",
+      "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
+      "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/klona": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz",
+      "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/knitwork": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/knitwork/-/knitwork-1.3.0.tgz",
+      "integrity": "sha512-4LqMNoONzR43B1W0ek0fhXMsDNW/zxa1NdFAVMY+k28pgZLovR4G3PB5MrpTxCy1QaZCqNoiaKPr5w5qZHfSNw==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/launch-editor": {
+      "version": "2.13.2",
+      "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.13.2.tgz",
+      "integrity": "sha512-4VVDnbOpLXy/s8rdRCSXb+zfMeFR0WlJWpET1iA9CQdlZDfwyLjUuGQzXU4VeOoey6AicSAluWan7Etga6Kcmg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "picocolors": "^1.1.1",
+        "shell-quote": "^1.8.3"
+      }
+    },
+    "node_modules/lazystream": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz",
+      "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "readable-stream": "^2.0.5"
+      },
+      "engines": {
+        "node": ">= 0.6.3"
+      }
+    },
+    "node_modules/lazystream/node_modules/readable-stream": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+      "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      }
+    },
+    "node_modules/lazystream/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/lazystream/node_modules/string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "node_modules/lilconfig": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
+      "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antonk52"
+      }
+    },
+    "node_modules/linkedom": {
+      "version": "0.18.12",
+      "resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.18.12.tgz",
+      "integrity": "sha512-jalJsOwIKuQJSeTvsgzPe9iJzyfVaEJiEXl+25EkKevsULHvMJzpNqwvj1jOESWdmgKDiXObyjOYwlUqG7wo1Q==",
+      "license": "ISC",
+      "dependencies": {
+        "css-select": "^5.1.0",
+        "cssom": "^0.5.0",
+        "html-escaper": "^3.0.3",
+        "htmlparser2": "^10.0.0",
+        "uhyphen": "^0.2.0"
+      },
+      "engines": {
+        "node": ">=16"
+      },
+      "peerDependencies": {
+        "canvas": ">= 2"
+      },
+      "peerDependenciesMeta": {
+        "canvas": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/listhen": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/listhen/-/listhen-1.9.1.tgz",
+      "integrity": "sha512-4EhoyVcXEpNlY5HJRSQpH7Rba94M8N2JmI62ePjl0lrJKXSfG0F1FAgHGxBoz/T3pe41sUEwkIRRIcaUL0/Ofw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@parcel/watcher": "^2.5.6",
+        "@parcel/watcher-wasm": "^2.5.6",
+        "citty": "^0.2.2",
+        "consola": "^3.4.2",
+        "crossws": ">=0.2.0 <0.5.0",
+        "defu": "^6.1.6",
+        "get-port-please": "^3.2.0",
+        "h3": "^1.15.11",
+        "http-shutdown": "^1.2.2",
+        "jiti": "^2.6.1",
+        "mlly": "^1.8.2",
+        "node-forge": "^1.4.0",
+        "pathe": "^2.0.3",
+        "std-env": "^4.0.0",
+        "tinyclip": "^0.1.12",
+        "ufo": "^1.6.3",
+        "untun": "^0.1.3",
+        "uqr": "^0.1.2"
+      },
+      "bin": {
+        "listen": "bin/listhen.mjs",
+        "listhen": "bin/listhen.mjs"
+      }
+    },
+    "node_modules/local-pkg": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz",
+      "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "mlly": "^1.7.4",
+        "pkg-types": "^2.3.0",
+        "quansync": "^0.2.11"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/lodash": {
+      "version": "4.18.1",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
+      "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/lodash.defaults": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
+      "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/lodash.isarguments": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
+      "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/lodash.memoize": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
+      "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/lodash.uniq": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
+      "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/longest-streak": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz",
+      "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/lru-cache": {
+      "version": "11.3.5",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz",
+      "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==",
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": "20 || >=22"
+      }
+    },
+    "node_modules/magic-regexp": {
+      "version": "0.10.0",
+      "resolved": "https://registry.npmjs.org/magic-regexp/-/magic-regexp-0.10.0.tgz",
+      "integrity": "sha512-Uly1Bu4lO1hwHUW0CQeSWuRtzCMNO00CmXtS8N6fyvB3B979GOEEeAkiTUDsmbYLAbvpUS/Kt5c4ibosAzVyVg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "estree-walker": "^3.0.3",
+        "magic-string": "^0.30.12",
+        "mlly": "^1.7.2",
+        "regexp-tree": "^0.1.27",
+        "type-level-regexp": "~0.1.17",
+        "ufo": "^1.5.4",
+        "unplugin": "^2.0.0"
+      }
+    },
+    "node_modules/magic-regexp/node_modules/unplugin": {
+      "version": "2.3.11",
+      "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz",
+      "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@jridgewell/remapping": "^2.3.5",
+        "acorn": "^8.15.0",
+        "picomatch": "^4.0.3",
+        "webpack-virtual-modules": "^0.6.2"
+      },
+      "engines": {
+        "node": ">=18.12.0"
+      }
+    },
+    "node_modules/magic-string": {
+      "version": "0.30.21",
+      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+      "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.5.5"
+      }
+    },
+    "node_modules/magic-string-ast": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/magic-string-ast/-/magic-string-ast-1.0.3.tgz",
+      "integrity": "sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "magic-string": "^0.30.19"
+      },
+      "engines": {
+        "node": ">=20.19.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sxzz"
+      }
+    },
+    "node_modules/magicast": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz",
+      "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.29.0",
+        "@babel/types": "^7.29.0",
+        "source-map-js": "^1.2.1"
+      }
+    },
+    "node_modules/markdown-extensions": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz",
+      "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/markdown-table": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz",
+      "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/mdast-util-definitions": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz",
+      "integrity": "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/mdast": "^4.0.0",
+        "@types/unist": "^3.0.0",
+        "unist-util-visit": "^5.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-directive": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.1.0.tgz",
+      "integrity": "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/mdast": "^4.0.0",
+        "@types/unist": "^3.0.0",
+        "ccount": "^2.0.0",
+        "devlop": "^1.0.0",
+        "mdast-util-from-markdown": "^2.0.0",
+        "mdast-util-to-markdown": "^2.0.0",
+        "parse-entities": "^4.0.0",
+        "stringify-entities": "^4.0.0",
+        "unist-util-visit-parents": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-find-and-replace": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz",
+      "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/mdast": "^4.0.0",
+        "escape-string-regexp": "^5.0.0",
+        "unist-util-is": "^6.0.0",
+        "unist-util-visit-parents": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-from-markdown": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz",
+      "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/mdast": "^4.0.0",
+        "@types/unist": "^3.0.0",
+        "decode-named-character-reference": "^1.0.0",
+        "devlop": "^1.0.0",
+        "mdast-util-to-string": "^4.0.0",
+        "micromark": "^4.0.0",
+        "micromark-util-decode-numeric-character-reference": "^2.0.0",
+        "micromark-util-decode-string": "^2.0.0",
+        "micromark-util-normalize-identifier": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0",
+        "unist-util-stringify-position": "^4.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-gfm": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz",
+      "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==",
+      "license": "MIT",
+      "dependencies": {
+        "mdast-util-from-markdown": "^2.0.0",
+        "mdast-util-gfm-autolink-literal": "^2.0.0",
+        "mdast-util-gfm-footnote": "^2.0.0",
+        "mdast-util-gfm-strikethrough": "^2.0.0",
+        "mdast-util-gfm-table": "^2.0.0",
+        "mdast-util-gfm-task-list-item": "^2.0.0",
+        "mdast-util-to-markdown": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-gfm-autolink-literal": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz",
+      "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/mdast": "^4.0.0",
+        "ccount": "^2.0.0",
+        "devlop": "^1.0.0",
+        "mdast-util-find-and-replace": "^3.0.0",
+        "micromark-util-character": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-gfm-footnote": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz",
+      "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/mdast": "^4.0.0",
+        "devlop": "^1.1.0",
+        "mdast-util-from-markdown": "^2.0.0",
+        "mdast-util-to-markdown": "^2.0.0",
+        "micromark-util-normalize-identifier": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-gfm-strikethrough": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz",
+      "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/mdast": "^4.0.0",
+        "mdast-util-from-markdown": "^2.0.0",
+        "mdast-util-to-markdown": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-gfm-table": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz",
+      "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/mdast": "^4.0.0",
+        "devlop": "^1.0.0",
+        "markdown-table": "^3.0.0",
+        "mdast-util-from-markdown": "^2.0.0",
+        "mdast-util-to-markdown": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-gfm-task-list-item": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz",
+      "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/mdast": "^4.0.0",
+        "devlop": "^1.0.0",
+        "mdast-util-from-markdown": "^2.0.0",
+        "mdast-util-to-markdown": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-mdx": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz",
+      "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==",
+      "license": "MIT",
+      "dependencies": {
+        "mdast-util-from-markdown": "^2.0.0",
+        "mdast-util-mdx-expression": "^2.0.0",
+        "mdast-util-mdx-jsx": "^3.0.0",
+        "mdast-util-mdxjs-esm": "^2.0.0",
+        "mdast-util-to-markdown": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-mdx-expression": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz",
+      "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree-jsx": "^1.0.0",
+        "@types/hast": "^3.0.0",
+        "@types/mdast": "^4.0.0",
+        "devlop": "^1.0.0",
+        "mdast-util-from-markdown": "^2.0.0",
+        "mdast-util-to-markdown": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-mdx-jsx": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz",
+      "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree-jsx": "^1.0.0",
+        "@types/hast": "^3.0.0",
+        "@types/mdast": "^4.0.0",
+        "@types/unist": "^3.0.0",
+        "ccount": "^2.0.0",
+        "devlop": "^1.1.0",
+        "mdast-util-from-markdown": "^2.0.0",
+        "mdast-util-to-markdown": "^2.0.0",
+        "parse-entities": "^4.0.0",
+        "stringify-entities": "^4.0.0",
+        "unist-util-stringify-position": "^4.0.0",
+        "vfile-message": "^4.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-mdxjs-esm": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz",
+      "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree-jsx": "^1.0.0",
+        "@types/hast": "^3.0.0",
+        "@types/mdast": "^4.0.0",
+        "devlop": "^1.0.0",
+        "mdast-util-from-markdown": "^2.0.0",
+        "mdast-util-to-markdown": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-phrasing": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz",
+      "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/mdast": "^4.0.0",
+        "unist-util-is": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-to-hast": {
+      "version": "13.2.1",
+      "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz",
+      "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "@types/mdast": "^4.0.0",
+        "@ungap/structured-clone": "^1.0.0",
+        "devlop": "^1.0.0",
+        "micromark-util-sanitize-uri": "^2.0.0",
+        "trim-lines": "^3.0.0",
+        "unist-util-position": "^5.0.0",
+        "unist-util-visit": "^5.0.0",
+        "vfile": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-to-markdown": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz",
+      "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/mdast": "^4.0.0",
+        "@types/unist": "^3.0.0",
+        "longest-streak": "^3.0.0",
+        "mdast-util-phrasing": "^4.0.0",
+        "mdast-util-to-string": "^4.0.0",
+        "micromark-util-classify-character": "^2.0.0",
+        "micromark-util-decode-string": "^2.0.0",
+        "unist-util-visit": "^5.0.0",
+        "zwitch": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdast-util-to-string": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz",
+      "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/mdast": "^4.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/mdn-data": {
+      "version": "2.27.1",
+      "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz",
+      "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==",
+      "license": "CC0-1.0"
+    },
+    "node_modules/merge-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+      "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/micromark": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz",
+      "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@types/debug": "^4.0.0",
+        "debug": "^4.0.0",
+        "decode-named-character-reference": "^1.0.0",
+        "devlop": "^1.0.0",
+        "micromark-core-commonmark": "^2.0.0",
+        "micromark-factory-space": "^2.0.0",
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-chunked": "^2.0.0",
+        "micromark-util-combine-extensions": "^2.0.0",
+        "micromark-util-decode-numeric-character-reference": "^2.0.0",
+        "micromark-util-encode": "^2.0.0",
+        "micromark-util-normalize-identifier": "^2.0.0",
+        "micromark-util-resolve-all": "^2.0.0",
+        "micromark-util-sanitize-uri": "^2.0.0",
+        "micromark-util-subtokenize": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-core-commonmark": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz",
+      "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "decode-named-character-reference": "^1.0.0",
+        "devlop": "^1.0.0",
+        "micromark-factory-destination": "^2.0.0",
+        "micromark-factory-label": "^2.0.0",
+        "micromark-factory-space": "^2.0.0",
+        "micromark-factory-title": "^2.0.0",
+        "micromark-factory-whitespace": "^2.0.0",
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-chunked": "^2.0.0",
+        "micromark-util-classify-character": "^2.0.0",
+        "micromark-util-html-tag-name": "^2.0.0",
+        "micromark-util-normalize-identifier": "^2.0.0",
+        "micromark-util-resolve-all": "^2.0.0",
+        "micromark-util-subtokenize": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-extension-directive": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.2.tgz",
+      "integrity": "sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==",
+      "license": "MIT",
+      "dependencies": {
+        "devlop": "^1.0.0",
+        "micromark-factory-space": "^2.0.0",
+        "micromark-factory-whitespace": "^2.0.0",
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0",
+        "parse-entities": "^4.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/micromark-extension-gfm": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz",
+      "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==",
+      "license": "MIT",
+      "dependencies": {
+        "micromark-extension-gfm-autolink-literal": "^2.0.0",
+        "micromark-extension-gfm-footnote": "^2.0.0",
+        "micromark-extension-gfm-strikethrough": "^2.0.0",
+        "micromark-extension-gfm-table": "^2.0.0",
+        "micromark-extension-gfm-tagfilter": "^2.0.0",
+        "micromark-extension-gfm-task-list-item": "^2.0.0",
+        "micromark-util-combine-extensions": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/micromark-extension-gfm-autolink-literal": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz",
+      "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==",
+      "license": "MIT",
+      "dependencies": {
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-sanitize-uri": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/micromark-extension-gfm-footnote": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz",
+      "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==",
+      "license": "MIT",
+      "dependencies": {
+        "devlop": "^1.0.0",
+        "micromark-core-commonmark": "^2.0.0",
+        "micromark-factory-space": "^2.0.0",
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-normalize-identifier": "^2.0.0",
+        "micromark-util-sanitize-uri": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/micromark-extension-gfm-strikethrough": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz",
+      "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==",
+      "license": "MIT",
+      "dependencies": {
+        "devlop": "^1.0.0",
+        "micromark-util-chunked": "^2.0.0",
+        "micromark-util-classify-character": "^2.0.0",
+        "micromark-util-resolve-all": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/micromark-extension-gfm-table": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz",
+      "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==",
+      "license": "MIT",
+      "dependencies": {
+        "devlop": "^1.0.0",
+        "micromark-factory-space": "^2.0.0",
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/micromark-extension-gfm-tagfilter": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz",
+      "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==",
+      "license": "MIT",
+      "dependencies": {
+        "micromark-util-types": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/micromark-extension-gfm-task-list-item": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz",
+      "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==",
+      "license": "MIT",
+      "dependencies": {
+        "devlop": "^1.0.0",
+        "micromark-factory-space": "^2.0.0",
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/micromark-extension-mdx-expression": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz",
+      "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0",
+        "devlop": "^1.0.0",
+        "micromark-factory-mdx-expression": "^2.0.0",
+        "micromark-factory-space": "^2.0.0",
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-events-to-acorn": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-extension-mdx-jsx": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz",
+      "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0",
+        "devlop": "^1.0.0",
+        "estree-util-is-identifier-name": "^3.0.0",
+        "micromark-factory-mdx-expression": "^2.0.0",
+        "micromark-factory-space": "^2.0.0",
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-events-to-acorn": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0",
+        "vfile-message": "^4.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/micromark-extension-mdx-md": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz",
+      "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==",
+      "license": "MIT",
+      "dependencies": {
+        "micromark-util-types": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/micromark-extension-mdxjs": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz",
+      "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==",
+      "license": "MIT",
+      "dependencies": {
+        "acorn": "^8.0.0",
+        "acorn-jsx": "^5.0.0",
+        "micromark-extension-mdx-expression": "^3.0.0",
+        "micromark-extension-mdx-jsx": "^3.0.0",
+        "micromark-extension-mdx-md": "^2.0.0",
+        "micromark-extension-mdxjs-esm": "^3.0.0",
+        "micromark-util-combine-extensions": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/micromark-extension-mdxjs-esm": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz",
+      "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0",
+        "devlop": "^1.0.0",
+        "micromark-core-commonmark": "^2.0.0",
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-events-to-acorn": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0",
+        "unist-util-position-from-estree": "^2.0.0",
+        "vfile-message": "^4.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/micromark-factory-destination": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz",
+      "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-factory-label": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz",
+      "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "devlop": "^1.0.0",
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-factory-mdx-expression": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz",
+      "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0",
+        "devlop": "^1.0.0",
+        "micromark-factory-space": "^2.0.0",
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-events-to-acorn": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0",
+        "unist-util-position-from-estree": "^2.0.0",
+        "vfile-message": "^4.0.0"
+      }
+    },
+    "node_modules/micromark-factory-space": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz",
+      "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-factory-title": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz",
+      "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "micromark-factory-space": "^2.0.0",
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-factory-whitespace": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz",
+      "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "micromark-factory-space": "^2.0.0",
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-util-character": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz",
+      "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-util-chunked": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz",
+      "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "micromark-util-symbol": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-util-classify-character": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz",
+      "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-util-combine-extensions": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz",
+      "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "micromark-util-chunked": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-util-decode-numeric-character-reference": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz",
+      "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "micromark-util-symbol": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-util-decode-string": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz",
+      "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "decode-named-character-reference": "^1.0.0",
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-decode-numeric-character-reference": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-util-encode": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz",
+      "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/micromark-util-events-to-acorn": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz",
+      "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0",
+        "@types/unist": "^3.0.0",
+        "devlop": "^1.0.0",
+        "estree-util-visit": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0",
+        "vfile-message": "^4.0.0"
+      }
+    },
+    "node_modules/micromark-util-html-tag-name": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz",
+      "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/micromark-util-normalize-identifier": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz",
+      "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "micromark-util-symbol": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-util-resolve-all": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz",
+      "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "micromark-util-types": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-util-sanitize-uri": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz",
+      "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "micromark-util-character": "^2.0.0",
+        "micromark-util-encode": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-util-subtokenize": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz",
+      "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "devlop": "^1.0.0",
+        "micromark-util-chunked": "^2.0.0",
+        "micromark-util-symbol": "^2.0.0",
+        "micromark-util-types": "^2.0.0"
+      }
+    },
+    "node_modules/micromark-util-symbol": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz",
+      "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/micromark-util-types": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz",
+      "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==",
+      "funding": [
+        {
+          "type": "GitHub Sponsors",
+          "url": "https://github.com/sponsors/unifiedjs"
+        },
+        {
+          "type": "OpenCollective",
+          "url": "https://opencollective.com/unified"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/micromatch": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+      "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+      "license": "MIT",
+      "dependencies": {
+        "braces": "^3.0.3",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/micromatch/node_modules/picomatch": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+      "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/mime": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-4.1.0.tgz",
+      "integrity": "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==",
+      "funding": [
+        "https://github.com/sponsors/broofa"
+      ],
+      "license": "MIT",
+      "peer": true,
+      "bin": {
+        "mime": "bin/cli.js"
+      },
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.54.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+      "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
+      "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "mime-db": "^1.54.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/mimic-fn": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
+      "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "9.0.9",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+      "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
+      "license": "ISC",
+      "peer": true,
+      "dependencies": {
+        "brace-expansion": "^2.0.2"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/minipass": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
+      "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      }
+    },
+    "node_modules/minizlib": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz",
+      "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==",
+      "license": "MIT",
+      "dependencies": {
+        "minipass": "^7.1.2"
+      },
+      "engines": {
+        "node": ">= 18"
+      }
+    },
+    "node_modules/mlly": {
+      "version": "1.8.2",
+      "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz",
+      "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "acorn": "^8.16.0",
+        "pathe": "^2.0.3",
+        "pkg-types": "^1.3.1",
+        "ufo": "^1.6.3"
+      }
+    },
+    "node_modules/mlly/node_modules/confbox": {
+      "version": "0.1.8",
+      "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz",
+      "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/mlly/node_modules/pkg-types": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz",
+      "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "confbox": "^0.1.8",
+        "mlly": "^1.7.4",
+        "pathe": "^2.0.1"
+      }
+    },
+    "node_modules/mocked-exports": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/mocked-exports/-/mocked-exports-0.1.1.tgz",
+      "integrity": "sha512-aF7yRQr/Q0O2/4pIXm6PZ5G+jAd7QS4Yu8m+WEeEHGnbo+7mE36CbLSDQiXYV8bVL3NfmdeqPJct0tUlnjVSnA==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/mrmime": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
+      "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "license": "MIT"
+    },
+    "node_modules/muggle-string": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz",
+      "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==",
+      "license": "MIT"
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.11",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+      "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/nanotar": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/nanotar/-/nanotar-0.3.0.tgz",
+      "integrity": "sha512-Kv2JYYiCzt16Kt5QwAc9BFG89xfPNBx+oQL4GQXD9nLqPkZBiNaqaCWtwnbk/q7UVsTYevvM1b0UF8zmEI4pCg==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/neotraverse": {
+      "version": "0.6.18",
+      "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.18.tgz",
+      "integrity": "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/nitropack": {
+      "version": "2.13.3",
+      "resolved": "https://registry.npmjs.org/nitropack/-/nitropack-2.13.3.tgz",
+      "integrity": "sha512-C8vO7RxkU0AQ3HbYUumuG6MVM5JjRaBchke/rYFOp3EvrLtTBHZYhDVGECdpa27vNuOYRzm3GtQMn2YDOjDJLA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@cloudflare/kv-asset-handler": "^0.4.2",
+        "@rollup/plugin-alias": "^6.0.0",
+        "@rollup/plugin-commonjs": "^29.0.2",
+        "@rollup/plugin-inject": "^5.0.5",
+        "@rollup/plugin-json": "^6.1.0",
+        "@rollup/plugin-node-resolve": "^16.0.3",
+        "@rollup/plugin-replace": "^6.0.3",
+        "@rollup/plugin-terser": "^1.0.0",
+        "@vercel/nft": "^1.5.0",
+        "archiver": "^7.0.1",
+        "c12": "^3.3.4",
+        "chokidar": "^5.0.0",
+        "citty": "^0.2.2",
+        "compatx": "^0.2.0",
+        "confbox": "^0.2.4",
+        "consola": "^3.4.2",
+        "cookie-es": "^2.0.1",
+        "croner": "^10.0.1",
+        "crossws": "^0.3.5",
+        "db0": "^0.3.4",
+        "defu": "^6.1.6",
+        "destr": "^2.0.5",
+        "dot-prop": "^10.1.0",
+        "esbuild": "^0.27.5",
+        "escape-string-regexp": "^5.0.0",
+        "etag": "^1.8.1",
+        "exsolve": "^1.0.8",
+        "globby": "^16.2.0",
+        "gzip-size": "^7.0.0",
+        "h3": "^1.15.10",
+        "hookable": "^5.5.3",
+        "httpxy": "^0.5.0",
+        "ioredis": "^5.10.1",
+        "jiti": "^2.6.1",
+        "klona": "^2.0.6",
+        "knitwork": "^1.3.0",
+        "listhen": "^1.9.1",
+        "magic-string": "^0.30.21",
+        "magicast": "^0.5.2",
+        "mime": "^4.1.0",
+        "mlly": "^1.8.2",
+        "node-fetch-native": "^1.6.7",
+        "node-mock-http": "^1.0.4",
+        "ofetch": "^1.5.1",
+        "ohash": "^2.0.11",
+        "pathe": "^2.0.3",
+        "perfect-debounce": "^2.1.0",
+        "pkg-types": "^2.3.0",
+        "pretty-bytes": "^7.1.0",
+        "radix3": "^1.1.2",
+        "rollup": "^4.60.1",
+        "rollup-plugin-visualizer": "^7.0.1",
+        "scule": "^1.3.0",
+        "semver": "^7.7.4",
+        "serve-placeholder": "^2.0.2",
+        "serve-static": "^2.2.1",
+        "source-map": "^0.7.6",
+        "std-env": "^4.0.0",
+        "ufo": "^1.6.3",
+        "ultrahtml": "^1.6.0",
+        "uncrypto": "^0.1.3",
+        "unctx": "^2.5.0",
+        "unenv": "2.0.0-rc.24",
+        "unimport": "^6.0.2",
+        "unplugin-utils": "^0.3.1",
+        "unstorage": "^1.17.5",
+        "untyped": "^2.0.0",
+        "unwasm": "^0.5.3",
+        "youch": "^4.1.1",
+        "youch-core": "^0.3.3"
+      },
+      "bin": {
+        "nitro": "dist/cli/index.mjs",
+        "nitropack": "dist/cli/index.mjs"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "peerDependencies": {
+        "xml2js": "^0.6.2"
+      },
+      "peerDependenciesMeta": {
+        "xml2js": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/nitropack/node_modules/cookie-es": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-2.0.1.tgz",
+      "integrity": "sha512-aVf4A4hI2w70LnF7GG+7xDQUkliwiXWXFvTjkip4+b64ygDQ2sJPRSKFDHbxn8o0xu9QzPkMuuiWIXyFSE2slA==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/nitropack/node_modules/hookable": {
+      "version": "5.5.3",
+      "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
+      "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/nlcst-to-string": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz",
+      "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/nlcst": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/node-addon-api": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+      "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/node-fetch": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+      "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+      "license": "MIT",
+      "dependencies": {
+        "whatwg-url": "^5.0.0"
+      },
+      "engines": {
+        "node": "4.x || >=6.0.0"
+      },
+      "peerDependencies": {
+        "encoding": "^0.1.0"
+      },
+      "peerDependenciesMeta": {
+        "encoding": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/node-fetch-native": {
+      "version": "1.6.7",
+      "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz",
+      "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==",
+      "license": "MIT"
+    },
+    "node_modules/node-forge": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz",
+      "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==",
+      "license": "(BSD-3-Clause OR GPL-2.0)",
+      "peer": true,
+      "engines": {
+        "node": ">= 6.13.0"
+      }
+    },
+    "node_modules/node-gyp-build": {
+      "version": "4.8.4",
+      "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
+      "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
+      "license": "MIT",
+      "bin": {
+        "node-gyp-build": "bin.js",
+        "node-gyp-build-optional": "optional.js",
+        "node-gyp-build-test": "build-test.js"
+      }
+    },
+    "node_modules/node-mock-http": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.4.tgz",
+      "integrity": "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==",
+      "license": "MIT"
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.36",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz",
+      "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==",
+      "license": "MIT"
+    },
+    "node_modules/nopt": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz",
+      "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==",
+      "license": "ISC",
+      "dependencies": {
+        "abbrev": "^3.0.0"
+      },
+      "bin": {
+        "nopt": "bin/nopt.js"
+      },
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/npm-run-path": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
+      "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "path-key": "^4.0.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/npm-run-path/node_modules/path-key": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
+      "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/nth-check": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "boolbase": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/nth-check?sponsor=1"
+      }
+    },
+    "node_modules/nuxt": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/nuxt/-/nuxt-4.4.2.tgz",
+      "integrity": "sha512-iWVFpr/YEqVU/CenqIHMnIkvb2HE/9f+q8oxZ+pj2et+60NljGRClCgnmbvGPdmNFE0F1bEhoBCYfqbDOCim3Q==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@dxup/nuxt": "^0.4.0",
+        "@nuxt/cli": "^3.34.0",
+        "@nuxt/devtools": "^3.2.3",
+        "@nuxt/kit": "4.4.2",
+        "@nuxt/nitro-server": "4.4.2",
+        "@nuxt/schema": "4.4.2",
+        "@nuxt/telemetry": "^2.7.0",
+        "@nuxt/vite-builder": "4.4.2",
+        "@unhead/vue": "^2.1.12",
+        "@vue/shared": "^3.5.30",
+        "c12": "^3.3.3",
+        "chokidar": "^5.0.0",
+        "compatx": "^0.2.0",
+        "consola": "^3.4.2",
+        "cookie-es": "^2.0.0",
+        "defu": "^6.1.4",
+        "devalue": "^5.6.3",
+        "errx": "^0.1.0",
+        "escape-string-regexp": "^5.0.0",
+        "exsolve": "^1.0.8",
+        "hookable": "^6.0.1",
+        "ignore": "^7.0.5",
+        "impound": "^1.1.5",
+        "jiti": "^2.6.1",
+        "klona": "^2.0.6",
+        "knitwork": "^1.3.0",
+        "magic-string": "^0.30.21",
+        "mlly": "^1.8.1",
+        "nanotar": "^0.3.0",
+        "nypm": "^0.6.5",
+        "ofetch": "^1.5.1",
+        "ohash": "^2.0.11",
+        "on-change": "^6.0.2",
+        "oxc-minify": "^0.117.0",
+        "oxc-parser": "^0.117.0",
+        "oxc-transform": "^0.117.0",
+        "oxc-walker": "^0.7.0",
+        "pathe": "^2.0.3",
+        "perfect-debounce": "^2.1.0",
+        "picomatch": "^4.0.3",
+        "pkg-types": "^2.3.0",
+        "rou3": "^0.8.1",
+        "scule": "^1.3.0",
+        "semver": "^7.7.4",
+        "std-env": "^4.0.0",
+        "tinyglobby": "^0.2.15",
+        "ufo": "^1.6.3",
+        "ultrahtml": "^1.6.0",
+        "uncrypto": "^0.1.3",
+        "unctx": "^2.5.0",
+        "unimport": "^6.0.1",
+        "unplugin": "^3.0.0",
+        "unrouting": "^0.1.5",
+        "untyped": "^2.0.0",
+        "vue": "^3.5.30",
+        "vue-router": "^5.0.3"
+      },
+      "bin": {
+        "nuxi": "bin/nuxt.mjs",
+        "nuxt": "bin/nuxt.mjs"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "peerDependencies": {
+        "@parcel/watcher": "^2.1.0",
+        "@types/node": ">=18.12.0"
+      },
+      "peerDependenciesMeta": {
+        "@parcel/watcher": {
+          "optional": true
+        },
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/nuxt/node_modules/@vue/devtools-api": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.1.1.tgz",
+      "integrity": "sha512-bsDMJ07b3GN1puVwJb/fyFnj/U2imyswK5UQVLZwVl7O05jDrt6BHxeG5XffmOOdasOj/bOmIjxJvGPxU7pcqw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@vue/devtools-kit": "^8.1.1"
+      }
+    },
+    "node_modules/nuxt/node_modules/cookie-es": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-2.0.1.tgz",
+      "integrity": "sha512-aVf4A4hI2w70LnF7GG+7xDQUkliwiXWXFvTjkip4+b64ygDQ2sJPRSKFDHbxn8o0xu9QzPkMuuiWIXyFSE2slA==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/nuxt/node_modules/vue-router": {
+      "version": "5.0.4",
+      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.0.4.tgz",
+      "integrity": "sha512-lCqDLCI2+fKVRl2OzXuzdSWmxXFLQRxQbmHugnRpTMyYiT+hNaycV0faqG5FBHDXoYrZ6MQcX87BvbY8mQ20Bg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/generator": "^7.28.6",
+        "@vue-macros/common": "^3.1.1",
+        "@vue/devtools-api": "^8.0.6",
+        "ast-walker-scope": "^0.8.3",
+        "chokidar": "^5.0.0",
+        "json5": "^2.2.3",
+        "local-pkg": "^1.1.2",
+        "magic-string": "^0.30.21",
+        "mlly": "^1.8.0",
+        "muggle-string": "^0.4.1",
+        "pathe": "^2.0.3",
+        "picomatch": "^4.0.3",
+        "scule": "^1.3.0",
+        "tinyglobby": "^0.2.15",
+        "unplugin": "^3.0.0",
+        "unplugin-utils": "^0.3.1",
+        "yaml": "^2.8.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/posva"
+      },
+      "peerDependencies": {
+        "@pinia/colada": ">=0.21.2",
+        "@vue/compiler-sfc": "^3.5.17",
+        "pinia": "^3.0.4",
+        "vue": "^3.5.0"
+      },
+      "peerDependenciesMeta": {
+        "@pinia/colada": {
+          "optional": true
+        },
+        "@vue/compiler-sfc": {
+          "optional": true
+        },
+        "pinia": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/nypm": {
+      "version": "0.6.5",
+      "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.5.tgz",
+      "integrity": "sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "citty": "^0.2.0",
+        "pathe": "^2.0.3",
+        "tinyexec": "^1.0.2"
+      },
+      "bin": {
+        "nypm": "dist/cli.mjs"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/obug": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz",
+      "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==",
+      "funding": [
+        "https://github.com/sponsors/sxzz",
+        "https://opencollective.com/debug"
+      ],
+      "license": "MIT"
+    },
+    "node_modules/ofetch": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz",
+      "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==",
+      "license": "MIT",
+      "dependencies": {
+        "destr": "^2.0.5",
+        "node-fetch-native": "^1.6.7",
+        "ufo": "^1.6.1"
+      }
+    },
+    "node_modules/ohash": {
+      "version": "2.0.11",
+      "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz",
+      "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==",
+      "license": "MIT"
+    },
+    "node_modules/on-change": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/on-change/-/on-change-6.0.2.tgz",
+      "integrity": "sha512-08+12qcOVEA0fS9g/VxKS27HaT94nRutUT77J2dr8zv/unzXopvhBuF8tNLWsoLQ5IgrQ6eptGeGqUYat82U1w==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/on-change?sponsor=1"
+      }
+    },
+    "node_modules/on-finished": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+      "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "ee-first": "1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/onetime": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
+      "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "mimic-fn": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/oniguruma-parser": {
+      "version": "0.12.1",
+      "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz",
+      "integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==",
+      "license": "MIT"
+    },
+    "node_modules/oniguruma-to-es": {
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.4.tgz",
+      "integrity": "sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==",
+      "license": "MIT",
+      "dependencies": {
+        "oniguruma-parser": "^0.12.1",
+        "regex": "^6.0.1",
+        "regex-recursion": "^6.0.2"
+      }
+    },
+    "node_modules/open": {
+      "version": "11.0.0",
+      "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz",
+      "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "default-browser": "^5.4.0",
+        "define-lazy-prop": "^3.0.0",
+        "is-in-ssh": "^1.0.0",
+        "is-inside-container": "^1.0.0",
+        "powershell-utils": "^0.1.0",
+        "wsl-utils": "^0.3.0"
+      },
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/oxc-minify": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/oxc-minify/-/oxc-minify-0.117.0.tgz",
+      "integrity": "sha512-JHsv/b+bmBJkAzkHXgTN7RThloVxLHPT0ojHfjqxVeHuQB7LPpLUbJ2qfwz37sto9stZ9+AVwUP4b3gtR7p/Tw==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/Boshen"
+      },
+      "optionalDependencies": {
+        "@oxc-minify/binding-android-arm-eabi": "0.117.0",
+        "@oxc-minify/binding-android-arm64": "0.117.0",
+        "@oxc-minify/binding-darwin-arm64": "0.117.0",
+        "@oxc-minify/binding-darwin-x64": "0.117.0",
+        "@oxc-minify/binding-freebsd-x64": "0.117.0",
+        "@oxc-minify/binding-linux-arm-gnueabihf": "0.117.0",
+        "@oxc-minify/binding-linux-arm-musleabihf": "0.117.0",
+        "@oxc-minify/binding-linux-arm64-gnu": "0.117.0",
+        "@oxc-minify/binding-linux-arm64-musl": "0.117.0",
+        "@oxc-minify/binding-linux-ppc64-gnu": "0.117.0",
+        "@oxc-minify/binding-linux-riscv64-gnu": "0.117.0",
+        "@oxc-minify/binding-linux-riscv64-musl": "0.117.0",
+        "@oxc-minify/binding-linux-s390x-gnu": "0.117.0",
+        "@oxc-minify/binding-linux-x64-gnu": "0.117.0",
+        "@oxc-minify/binding-linux-x64-musl": "0.117.0",
+        "@oxc-minify/binding-openharmony-arm64": "0.117.0",
+        "@oxc-minify/binding-wasm32-wasi": "0.117.0",
+        "@oxc-minify/binding-win32-arm64-msvc": "0.117.0",
+        "@oxc-minify/binding-win32-ia32-msvc": "0.117.0",
+        "@oxc-minify/binding-win32-x64-msvc": "0.117.0"
+      }
+    },
+    "node_modules/oxc-parser": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.117.0.tgz",
+      "integrity": "sha512-l3cbgK5wUvWDVNWM/JFU77qDdGZK1wudnLsFcrRyNo/bL1CyU8pC25vDhMHikVY29lbK2InTWsX42RxVSutUdQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@oxc-project/types": "^0.117.0"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/Boshen"
+      },
+      "optionalDependencies": {
+        "@oxc-parser/binding-android-arm-eabi": "0.117.0",
+        "@oxc-parser/binding-android-arm64": "0.117.0",
+        "@oxc-parser/binding-darwin-arm64": "0.117.0",
+        "@oxc-parser/binding-darwin-x64": "0.117.0",
+        "@oxc-parser/binding-freebsd-x64": "0.117.0",
+        "@oxc-parser/binding-linux-arm-gnueabihf": "0.117.0",
+        "@oxc-parser/binding-linux-arm-musleabihf": "0.117.0",
+        "@oxc-parser/binding-linux-arm64-gnu": "0.117.0",
+        "@oxc-parser/binding-linux-arm64-musl": "0.117.0",
+        "@oxc-parser/binding-linux-ppc64-gnu": "0.117.0",
+        "@oxc-parser/binding-linux-riscv64-gnu": "0.117.0",
+        "@oxc-parser/binding-linux-riscv64-musl": "0.117.0",
+        "@oxc-parser/binding-linux-s390x-gnu": "0.117.0",
+        "@oxc-parser/binding-linux-x64-gnu": "0.117.0",
+        "@oxc-parser/binding-linux-x64-musl": "0.117.0",
+        "@oxc-parser/binding-openharmony-arm64": "0.117.0",
+        "@oxc-parser/binding-wasm32-wasi": "0.117.0",
+        "@oxc-parser/binding-win32-arm64-msvc": "0.117.0",
+        "@oxc-parser/binding-win32-ia32-msvc": "0.117.0",
+        "@oxc-parser/binding-win32-x64-msvc": "0.117.0"
+      }
+    },
+    "node_modules/oxc-transform": {
+      "version": "0.117.0",
+      "resolved": "https://registry.npmjs.org/oxc-transform/-/oxc-transform-0.117.0.tgz",
+      "integrity": "sha512-u1Stl2uhDh9bFuOGjGXQIqx46IRUNMyHQkq59LayXNGS2flNv7RpZpRSWs5S5deuNP6jJZ12gtMBze+m4dOhmw==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/Boshen"
+      },
+      "optionalDependencies": {
+        "@oxc-transform/binding-android-arm-eabi": "0.117.0",
+        "@oxc-transform/binding-android-arm64": "0.117.0",
+        "@oxc-transform/binding-darwin-arm64": "0.117.0",
+        "@oxc-transform/binding-darwin-x64": "0.117.0",
+        "@oxc-transform/binding-freebsd-x64": "0.117.0",
+        "@oxc-transform/binding-linux-arm-gnueabihf": "0.117.0",
+        "@oxc-transform/binding-linux-arm-musleabihf": "0.117.0",
+        "@oxc-transform/binding-linux-arm64-gnu": "0.117.0",
+        "@oxc-transform/binding-linux-arm64-musl": "0.117.0",
+        "@oxc-transform/binding-linux-ppc64-gnu": "0.117.0",
+        "@oxc-transform/binding-linux-riscv64-gnu": "0.117.0",
+        "@oxc-transform/binding-linux-riscv64-musl": "0.117.0",
+        "@oxc-transform/binding-linux-s390x-gnu": "0.117.0",
+        "@oxc-transform/binding-linux-x64-gnu": "0.117.0",
+        "@oxc-transform/binding-linux-x64-musl": "0.117.0",
+        "@oxc-transform/binding-openharmony-arm64": "0.117.0",
+        "@oxc-transform/binding-wasm32-wasi": "0.117.0",
+        "@oxc-transform/binding-win32-arm64-msvc": "0.117.0",
+        "@oxc-transform/binding-win32-ia32-msvc": "0.117.0",
+        "@oxc-transform/binding-win32-x64-msvc": "0.117.0"
+      }
+    },
+    "node_modules/oxc-walker": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/oxc-walker/-/oxc-walker-0.7.0.tgz",
+      "integrity": "sha512-54B4KUhrzbzc4sKvKwVYm7E2PgeROpGba0/2nlNZMqfDyca+yOor5IMb4WLGBatGDT0nkzYdYuzylg7n3YfB7A==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "magic-regexp": "^0.10.0"
+      },
+      "peerDependencies": {
+        "oxc-parser": ">=0.98.0"
+      }
+    },
+    "node_modules/p-limit": {
+      "version": "7.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.0.tgz",
+      "integrity": "sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw==",
+      "license": "MIT",
+      "dependencies": {
+        "yocto-queue": "^1.2.1"
+      },
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-queue": {
+      "version": "9.1.2",
+      "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.1.2.tgz",
+      "integrity": "sha512-ktsDOALzTYTWWF1PbkNVg2rOt+HaOaMWJMUnt7T3qf5tvZ1L8dBW3tObzprBcXNMKkwj+yFSLqHso0x+UFcJXw==",
+      "license": "MIT",
+      "dependencies": {
+        "eventemitter3": "^5.0.1",
+        "p-timeout": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-timeout": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.1.tgz",
+      "integrity": "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/package-json-from-dist": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+      "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+      "license": "BlueOak-1.0.0",
+      "peer": true
+    },
+    "node_modules/package-manager-detector": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz",
+      "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==",
+      "license": "MIT"
+    },
+    "node_modules/pagefind": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/pagefind/-/pagefind-1.4.0.tgz",
+      "integrity": "sha512-z2kY1mQlL4J8q5EIsQkLzQjilovKzfNVhX8De6oyE6uHpfFtyBaqUpcl/XzJC/4fjD8vBDyh1zolimIcVrCn9g==",
+      "license": "MIT",
+      "bin": {
+        "pagefind": "lib/runner/bin.cjs"
+      },
+      "optionalDependencies": {
+        "@pagefind/darwin-arm64": "1.4.0",
+        "@pagefind/darwin-x64": "1.4.0",
+        "@pagefind/freebsd-x64": "1.4.0",
+        "@pagefind/linux-arm64": "1.4.0",
+        "@pagefind/linux-x64": "1.4.0",
+        "@pagefind/windows-x64": "1.4.0"
+      }
+    },
+    "node_modules/parse-entities": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz",
+      "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "^2.0.0",
+        "character-entities-legacy": "^3.0.0",
+        "character-reference-invalid": "^2.0.0",
+        "decode-named-character-reference": "^1.0.0",
+        "is-alphanumerical": "^2.0.0",
+        "is-decimal": "^2.0.0",
+        "is-hexadecimal": "^2.0.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/parse-entities/node_modules/@types/unist": {
+      "version": "2.0.11",
+      "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz",
+      "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==",
+      "license": "MIT"
+    },
+    "node_modules/parse-latin": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz",
+      "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/nlcst": "^2.0.0",
+        "@types/unist": "^3.0.0",
+        "nlcst-to-string": "^4.0.0",
+        "unist-util-modify-children": "^4.0.0",
+        "unist-util-visit-children": "^3.0.0",
+        "vfile": "^6.0.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/parse5": {
+      "version": "7.3.0",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
+      "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
+      "license": "MIT",
+      "dependencies": {
+        "entities": "^6.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/parseurl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/path-browserify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
+      "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/path-expression-matcher": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz",
+      "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/NaturalIntelligence"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/path-scurry": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+      "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+      "license": "BlueOak-1.0.0",
+      "peer": true,
+      "dependencies": {
+        "lru-cache": "^10.2.0",
+        "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/path-scurry/node_modules/lru-cache": {
+      "version": "10.4.3",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+      "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+      "license": "ISC",
+      "peer": true
+    },
+    "node_modules/path-to-regexp": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
+      "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==",
+      "license": "MIT"
+    },
+    "node_modules/path-to-regexp-updated": {
+      "name": "path-to-regexp",
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
+      "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==",
+      "license": "MIT"
+    },
+    "node_modules/pathe": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+      "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/perfect-debounce": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz",
+      "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/piccolore": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/piccolore/-/piccolore-0.1.3.tgz",
+      "integrity": "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==",
+      "license": "ISC"
+    },
+    "node_modules/picocolors": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+      "license": "ISC"
+    },
+    "node_modules/picomatch": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+      "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pkg-types": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz",
+      "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "confbox": "^0.2.2",
+        "exsolve": "^1.0.7",
+        "pathe": "^2.0.3"
+      }
+    },
+    "node_modules/postcss": {
+      "version": "8.5.10",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz",
+      "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "nanoid": "^3.3.11",
+        "picocolors": "^1.1.1",
+        "source-map-js": "^1.2.1"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/postcss-calc": {
+      "version": "10.1.1",
+      "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-10.1.1.tgz",
+      "integrity": "sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "postcss-selector-parser": "^7.0.0",
+        "postcss-value-parser": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.12 || ^20.9 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.4.38"
+      }
+    },
+    "node_modules/postcss-calc/node_modules/postcss-selector-parser": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz",
+      "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postcss-colormin": {
+      "version": "7.0.9",
+      "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.9.tgz",
+      "integrity": "sha512-EZpoUlmbXQUpe+g4ZaGM2kjGlHrQ7Bjzb3xHcNrC9ysI1tGoib6DAYvxg6aB7MGxsjgLF+Qx/jwZQkJ5cKDvXA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@colordx/core": "^5.2.0",
+        "browserslist": "^4.28.2",
+        "caniuse-api": "^3.0.0",
+        "postcss-value-parser": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-convert-values": {
+      "version": "7.0.11",
+      "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-7.0.11.tgz",
+      "integrity": "sha512-H+s7P0f9jJylSysAHs3/5MhAx7GthDO05uw1h56L2xyEqpiLTFLEqBNw3PUYzD5p/AKwWaigCXf6FGELpOw9lw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "browserslist": "^4.28.2",
+        "postcss-value-parser": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-discard-comments": {
+      "version": "7.0.7",
+      "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-7.0.7.tgz",
+      "integrity": "sha512-FJhE3fSte7HaRNL4iwD8LTG9vWqj3puxXIdig6LfrFqc1TJRUhY4kXOkeTXZZfTXYny+k+SO7fd2fymj1wduJg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "postcss-selector-parser": "^7.1.1"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-discard-comments/node_modules/postcss-selector-parser": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz",
+      "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postcss-discard-duplicates": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-7.0.3.tgz",
+      "integrity": "sha512-9cRxXwhEM/aNZon1qZyToX4NmjbFbxOGbww+0CnbYFDbbPRGZ8jg4IbM8UlA+CzkXxM35itxyaHKNqBBg/RTDg==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-discard-empty": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-7.0.2.tgz",
+      "integrity": "sha512-NZFouOmOwtngJVgkNeI1LtkzFdYqIurxgy4wq3qNvIiXFURTZ3b/K7q3dP3QitlWQ5imHDQL0qSorItQhoxb1g==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-discard-overridden": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-7.0.2.tgz",
+      "integrity": "sha512-Ym01X4v6U3sY8X0P1J9P+RTar+7JyLTOzDrxKSeaArFsLmkVu4KcAKPBWDYRIyZ/q4jwpSPnOnekeSSqXSXKUw==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-merge-longhand": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-7.0.6.tgz",
+      "integrity": "sha512-lDsWeKRsssX/9vKFpingoRiuvGajtOGCJhs1kyaTJ5fzaVzs0aPPYe38UZ/ukMFEA5iuRIjQJHIkH2niYO3ubQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "postcss-value-parser": "^4.2.0",
+        "stylehacks": "^7.0.10"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-merge-rules": {
+      "version": "7.0.10",
+      "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-7.0.10.tgz",
+      "integrity": "sha512-UXYKxkg8Cy1so/evF7AE/25PNXZb3E0SrvjdbtbGf+MW+doLenKqRLQzz6YZW469ktiXK2MVLFWtel/DftCV0Q==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "browserslist": "^4.28.2",
+        "caniuse-api": "^3.0.0",
+        "cssnano-utils": "^5.0.2",
+        "postcss-selector-parser": "^7.1.1"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-merge-rules/node_modules/postcss-selector-parser": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz",
+      "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postcss-minify-font-values": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-7.0.2.tgz",
+      "integrity": "sha512-Z82NUmnvhPrvMUaHfkaAVBmWQq9F8Dox4Dy0LiwbaTxfmDUWLQtS+0WCgKViwdWCPPajiY9YzoQftgqKdXkM5g==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "postcss-value-parser": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-minify-gradients": {
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-7.0.4.tgz",
+      "integrity": "sha512-g8MNeNyN+lbwKy8DCtJ6zU6awBL0InBsSOaKmgZ1MdRLVItLQUNFNAzzzBnOp4qowOcyyB6GetTlQ0/0UNXvag==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@colordx/core": "^5.2.0",
+        "cssnano-utils": "^5.0.2",
+        "postcss-value-parser": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-minify-params": {
+      "version": "7.0.8",
+      "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-7.0.8.tgz",
+      "integrity": "sha512-DIUKM5DZGTmxN7KFKT+rxt0FdPDmRrdK/k3n3+6Po+N/QYn06juwagHcfOVBG0CfCHwcnI612GAUCZc3eT+ZEg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "browserslist": "^4.28.2",
+        "cssnano-utils": "^5.0.2",
+        "postcss-value-parser": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-minify-selectors": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-7.1.0.tgz",
+      "integrity": "sha512-HYl/6I0aL+UvpA10t65BSa7h+tVjBgE6oRI5N/3ylX3vtwvlDL67G3FT3vYDPnTksxr0riiyJcT0tBtyRVoloA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "browserslist": "^4.28.1",
+        "caniuse-api": "^3.0.0",
+        "cssesc": "^3.0.0",
+        "postcss-selector-parser": "^7.1.1"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-minify-selectors/node_modules/postcss-selector-parser": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz",
+      "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postcss-nested": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
+      "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "postcss-selector-parser": "^6.1.1"
+      },
+      "engines": {
+        "node": ">=12.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.2.14"
+      }
+    },
+    "node_modules/postcss-normalize-charset": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-7.0.2.tgz",
+      "integrity": "sha512-YoINoiR4YKlzfB95Y93b0DSxWy7FLw+1SADIaznMHb88AKizpzfF80tolmiDEbYr1UM4r4Hw+NZq37SwT5f3uw==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-normalize-display-values": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-7.0.2.tgz",
+      "integrity": "sha512-wu/NTSjnp8sX5TnEHVPN+eScjAtRs18ELtEduG+Ek3GxjeUDUT+VAA3PJjVIXBcVIk6fiLYFj2iKH0q99S3T2Q==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "postcss-value-parser": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-normalize-positions": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-7.0.3.tgz",
+      "integrity": "sha512-1CJI++oA3yK/fQlPUcEngUfcSWS08Pkt9fK+jVgL53mmtHDBHi0YiuB0m3D9BXwZjmfvCc2GQmFqCAF/CVcPzQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "postcss-value-parser": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-normalize-repeat-style": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-7.0.3.tgz",
+      "integrity": "sha512-RvImJ2Ml4LZSx31qC2C8LDiz65IgBNATtwEr9r3Aue+D0cCGbj4rjNojb/uGpEm4QxnOTzFqMvaDYuKiT1Cmpg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "postcss-value-parser": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-normalize-string": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-7.0.2.tgz",
+      "integrity": "sha512-FqtrUh2BU2MnVeLeWBbJ2rwOjuDnA91XvoImc1BbgMWIxdxiPTaquflBHsmFBA3xh3pC3wPZO9W5MaIc7wU/Xw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "postcss-value-parser": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-normalize-timing-functions": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-7.0.2.tgz",
+      "integrity": "sha512-5H5fpXBnMACEXzn7k9RP7qWZ1eWg8cuZkUuFygStY7icOj+UucwMWXeMmdkF/iITvTVa7fP85tdRCJeznpdFfQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "postcss-value-parser": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-normalize-unicode": {
+      "version": "7.0.8",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-7.0.8.tgz",
+      "integrity": "sha512-imCM3cwK3hvlAG4z1AzYM24m8BPA3/Jk/S71wfbn2I6+E2b+UwFaGvlNqydihXTSl3OFPeQXztqCzg+NGeSibQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "browserslist": "^4.28.2",
+        "postcss-value-parser": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-normalize-url": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-7.0.2.tgz",
+      "integrity": "sha512-bLnNY7t76NLRb9QQyCVmCN4qwoHxiq6vABH/CXav9wTuR6dNGHGQ72AyO/+h2quWxZk3l7BqxNL1vtDi9H6y1g==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "postcss-value-parser": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-normalize-whitespace": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-7.0.2.tgz",
+      "integrity": "sha512-TNSVkuhkeOhl36WruQlflxOb7HweoeZowSusNpfsM1+ZvqJ24Mc+xksu05ecMQxlu+0zgI8pyznO2EWqDCQbLA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "postcss-value-parser": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-ordered-values": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-7.0.3.tgz",
+      "integrity": "sha512-FTt6R9RF7NAYfpOHa2XFPm89FVuo5GiIbcfwOXFy1MYF38BeiNW9ke8ybw9Pk62eEsUlRVVbxHWA3B7ERYqOOA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "cssnano-utils": "^5.0.2",
+        "postcss-value-parser": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-reduce-initial": {
+      "version": "7.0.8",
+      "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-7.0.8.tgz",
+      "integrity": "sha512-VeVRmbgpgTZuRcDQdqnsB4iYTeS2dBRV07UdwK6V3x61F1xTQ2pgIzHBIR4rQYRlXRNKBTGYYhEL1eNA7w9vaQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "browserslist": "^4.28.2",
+        "caniuse-api": "^3.0.0"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-reduce-transforms": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-7.0.2.tgz",
+      "integrity": "sha512-OV5P9hMnf7kEkeXVXyS5ESqxbIls7a3TqFymUAV5JICO/9YCBEU+QQhQjZiDHaLwFdV7/CL481kVeBUk5FdY3w==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "postcss-value-parser": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-selector-parser": {
+      "version": "6.1.2",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
+      "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
+      "license": "MIT",
+      "dependencies": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postcss-svgo": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-7.1.2.tgz",
+      "integrity": "sha512-ixExc8m+/68yuSYQzV/1DgtTup/7nI2dN9eiDS5GMRUzeCH4q9UcqeZPwcSVhdf8ay9fRwXDUHwcY5/XzQSszQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "postcss-value-parser": "^4.2.0",
+        "svgo": "^4.0.1"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >= 18"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-unique-selectors": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-7.0.6.tgz",
+      "integrity": "sha512-cDxnYw1QuBMW5w3svZ0BlYF0IA4Amr+1JoTLXzu6vDFPNwohN2QU+sPZNx15b930LR7ce+/600h28/cYoxO9vw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "postcss-selector-parser": "^7.1.1"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/postcss-unique-selectors/node_modules/postcss-selector-parser": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz",
+      "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postcss-value-parser": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+      "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/powershell-utils": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz",
+      "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/prettier": {
+      "version": "3.8.3",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz",
+      "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "prettier": "bin/prettier.cjs"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/prettier/prettier?sponsor=1"
+      }
+    },
+    "node_modules/pretty-bytes": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-7.1.0.tgz",
+      "integrity": "sha512-nODzvTiYVRGRqAOvE84Vk5JDPyyxsVk0/fbA/bq7RqlnhksGpset09XTxbpvLTIjoaF7K8Z8DG8yHtKGTPSYRw==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/prismjs": {
+      "version": "1.30.0",
+      "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz",
+      "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/process": {
+      "version": "0.11.10",
+      "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+      "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">= 0.6.0"
+      }
+    },
+    "node_modules/process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/property-information": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz",
+      "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/punycode": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+      "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/quansync": {
+      "version": "0.2.11",
+      "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz",
+      "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/antfu"
+        },
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/sxzz"
+        }
+      ],
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/radix3": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz",
+      "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==",
+      "license": "MIT"
+    },
+    "node_modules/range-parser": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/rc9": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/rc9/-/rc9-3.0.1.tgz",
+      "integrity": "sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "defu": "^6.1.6",
+        "destr": "^2.0.5"
+      }
+    },
+    "node_modules/react": {
+      "version": "19.2.4",
+      "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
+      "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/react-dom": {
+      "version": "19.2.4",
+      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
+      "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
+      "license": "MIT",
+      "dependencies": {
+        "scheduler": "^0.27.0"
+      },
+      "peerDependencies": {
+        "react": "^19.2.4"
+      }
+    },
+    "node_modules/react-icons": {
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.6.0.tgz",
+      "integrity": "sha512-RH93p5ki6LfOiIt0UtDyNg/cee+HLVR6cHHtW3wALfo+eOHTp8RnU2kRkI6E+H19zMIs03DyxUG/GfZMOGvmiA==",
+      "license": "MIT",
+      "peerDependencies": {
+        "react": "*"
+      }
+    },
+    "node_modules/react-markdown": {
+      "version": "10.1.0",
+      "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz",
+      "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "@types/mdast": "^4.0.0",
+        "devlop": "^1.0.0",
+        "hast-util-to-jsx-runtime": "^2.0.0",
+        "html-url-attributes": "^3.0.0",
+        "mdast-util-to-hast": "^13.0.0",
+        "remark-parse": "^11.0.0",
+        "remark-rehype": "^11.0.0",
+        "unified": "^11.0.0",
+        "unist-util-visit": "^5.0.0",
+        "vfile": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      },
+      "peerDependencies": {
+        "@types/react": ">=18",
+        "react": ">=18"
+      }
+    },
+    "node_modules/react-refresh": {
+      "version": "0.18.0",
+      "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
+      "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/react-remove-scroll": {
+      "version": "2.7.2",
+      "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz",
+      "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==",
+      "license": "MIT",
+      "dependencies": {
+        "react-remove-scroll-bar": "^2.3.7",
+        "react-style-singleton": "^2.2.3",
+        "tslib": "^2.1.0",
+        "use-callback-ref": "^1.3.3",
+        "use-sidecar": "^1.1.3"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/react-remove-scroll-bar": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
+      "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
+      "license": "MIT",
+      "dependencies": {
+        "react-style-singleton": "^2.2.2",
+        "tslib": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/react-style-singleton": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
+      "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
+      "license": "MIT",
+      "dependencies": {
+        "get-nonce": "^1.0.0",
+        "tslib": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/readable-stream": {
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
+      "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "abort-controller": "^3.0.0",
+        "buffer": "^6.0.3",
+        "events": "^3.3.0",
+        "process": "^0.11.10",
+        "string_decoder": "^1.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/readdir-glob": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz",
+      "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "dependencies": {
+        "minimatch": "^5.1.0"
+      }
+    },
+    "node_modules/readdir-glob/node_modules/minimatch": {
+      "version": "5.1.9",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
+      "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
+      "license": "ISC",
+      "peer": true,
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
+      "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 20.19.0"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/recma-build-jsx": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz",
+      "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0",
+        "estree-util-build-jsx": "^3.0.0",
+        "vfile": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/recma-jsx": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.1.tgz",
+      "integrity": "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==",
+      "license": "MIT",
+      "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"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      },
+      "peerDependencies": {
+        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/recma-parse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz",
+      "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0",
+        "esast-util-from-js": "^2.0.0",
+        "unified": "^11.0.0",
+        "vfile": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/recma-stringify": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz",
+      "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0",
+        "estree-util-to-js": "^2.0.0",
+        "unified": "^11.0.0",
+        "vfile": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/redis-errors": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
+      "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/redis-parser": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
+      "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "redis-errors": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/regex": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz",
+      "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==",
+      "license": "MIT",
+      "dependencies": {
+        "regex-utilities": "^2.3.0"
+      }
+    },
+    "node_modules/regex-recursion": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz",
+      "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==",
+      "license": "MIT",
+      "dependencies": {
+        "regex-utilities": "^2.3.0"
+      }
+    },
+    "node_modules/regex-utilities": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz",
+      "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==",
+      "license": "MIT"
+    },
+    "node_modules/regexp-tree": {
+      "version": "0.1.27",
+      "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz",
+      "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==",
+      "license": "MIT",
+      "peer": true,
+      "bin": {
+        "regexp-tree": "bin/regexp-tree"
+      }
+    },
+    "node_modules/rehype": {
+      "version": "13.0.2",
+      "resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.2.tgz",
+      "integrity": "sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "rehype-parse": "^9.0.0",
+        "rehype-stringify": "^10.0.0",
+        "unified": "^11.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/rehype-expressive-code": {
+      "version": "0.41.7",
+      "resolved": "https://registry.npmjs.org/rehype-expressive-code/-/rehype-expressive-code-0.41.7.tgz",
+      "integrity": "sha512-25f8ZMSF1d9CMscX7Cft0TSQIqdwjce2gDOvQ+d/w0FovsMwrSt3ODP4P3Z7wO1jsIJ4eYyaDRnIR/27bd/EMQ==",
+      "license": "MIT",
+      "dependencies": {
+        "expressive-code": "^0.41.7"
+      }
+    },
+    "node_modules/rehype-format": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/rehype-format/-/rehype-format-5.0.1.tgz",
+      "integrity": "sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "hast-util-format": "^1.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/rehype-minify-whitespace": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/rehype-minify-whitespace/-/rehype-minify-whitespace-6.0.2.tgz",
+      "integrity": "sha512-Zk0pyQ06A3Lyxhe9vGtOtzz3Z0+qZ5+7icZ/PL/2x1SHPbKao5oB/g/rlc6BCTajqBb33JcOe71Ye1oFsuYbnw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "hast-util-minify-whitespace": "^1.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/rehype-parse": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz",
+      "integrity": "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "hast-util-from-html": "^2.0.0",
+        "unified": "^11.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/rehype-raw": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz",
+      "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "hast-util-raw": "^9.0.0",
+        "vfile": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/rehype-recma": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz",
+      "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0",
+        "@types/hast": "^3.0.0",
+        "hast-util-to-estree": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/rehype-remark": {
+      "version": "10.0.1",
+      "resolved": "https://registry.npmjs.org/rehype-remark/-/rehype-remark-10.0.1.tgz",
+      "integrity": "sha512-EmDndlb5NVwXGfUa4c9GPK+lXeItTilLhE6ADSaQuHr4JUlKw9MidzGzx4HpqZrNCt6vnHmEifXQiiA+CEnjYQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "@types/mdast": "^4.0.0",
+        "hast-util-to-mdast": "^10.0.0",
+        "unified": "^11.0.0",
+        "vfile": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/rehype-stringify": {
+      "version": "10.0.1",
+      "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz",
+      "integrity": "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "hast-util-to-html": "^9.0.0",
+        "unified": "^11.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/remark-directive": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-3.0.1.tgz",
+      "integrity": "sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/mdast": "^4.0.0",
+        "mdast-util-directive": "^3.0.0",
+        "micromark-extension-directive": "^3.0.0",
+        "unified": "^11.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/remark-gfm": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz",
+      "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/mdast": "^4.0.0",
+        "mdast-util-gfm": "^3.0.0",
+        "micromark-extension-gfm": "^3.0.0",
+        "remark-parse": "^11.0.0",
+        "remark-stringify": "^11.0.0",
+        "unified": "^11.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/remark-mdx": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz",
+      "integrity": "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==",
+      "license": "MIT",
+      "dependencies": {
+        "mdast-util-mdx": "^3.0.0",
+        "micromark-extension-mdxjs": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/remark-parse": {
+      "version": "11.0.0",
+      "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz",
+      "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/mdast": "^4.0.0",
+        "mdast-util-from-markdown": "^2.0.0",
+        "micromark-util-types": "^2.0.0",
+        "unified": "^11.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/remark-rehype": {
+      "version": "11.1.2",
+      "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz",
+      "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/hast": "^3.0.0",
+        "@types/mdast": "^4.0.0",
+        "mdast-util-to-hast": "^13.0.0",
+        "unified": "^11.0.0",
+        "vfile": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/remark-smartypants": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-3.0.2.tgz",
+      "integrity": "sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==",
+      "license": "MIT",
+      "dependencies": {
+        "retext": "^9.0.0",
+        "retext-smartypants": "^6.0.0",
+        "unified": "^11.0.4",
+        "unist-util-visit": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
+    "node_modules/remark-stringify": {
+      "version": "11.0.0",
+      "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz",
+      "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/mdast": "^4.0.0",
+        "mdast-util-to-markdown": "^2.0.0",
+        "unified": "^11.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/request-light": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.7.0.tgz",
+      "integrity": "sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/require-from-string": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+      "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/resolve": {
+      "version": "1.22.12",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz",
+      "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "is-core-module": "^2.16.1",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/resolve-from": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/retext": {
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz",
+      "integrity": "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/nlcst": "^2.0.0",
+        "retext-latin": "^4.0.0",
+        "retext-stringify": "^4.0.0",
+        "unified": "^11.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/retext-latin": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-4.0.0.tgz",
+      "integrity": "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/nlcst": "^2.0.0",
+        "parse-latin": "^7.0.0",
+        "unified": "^11.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/retext-smartypants": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.2.0.tgz",
+      "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/nlcst": "^2.0.0",
+        "nlcst-to-string": "^4.0.0",
+        "unist-util-visit": "^5.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/retext-stringify": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-4.0.0.tgz",
+      "integrity": "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/nlcst": "^2.0.0",
+        "nlcst-to-string": "^4.0.0",
+        "unified": "^11.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/reusify": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+      "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/rollup": {
+      "version": "4.60.2",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.2.tgz",
+      "integrity": "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "1.0.8"
+      },
+      "bin": {
+        "rollup": "dist/bin/rollup"
+      },
+      "engines": {
+        "node": ">=18.0.0",
+        "npm": ">=8.0.0"
+      },
+      "optionalDependencies": {
+        "@rollup/rollup-android-arm-eabi": "4.60.2",
+        "@rollup/rollup-android-arm64": "4.60.2",
+        "@rollup/rollup-darwin-arm64": "4.60.2",
+        "@rollup/rollup-darwin-x64": "4.60.2",
+        "@rollup/rollup-freebsd-arm64": "4.60.2",
+        "@rollup/rollup-freebsd-x64": "4.60.2",
+        "@rollup/rollup-linux-arm-gnueabihf": "4.60.2",
+        "@rollup/rollup-linux-arm-musleabihf": "4.60.2",
+        "@rollup/rollup-linux-arm64-gnu": "4.60.2",
+        "@rollup/rollup-linux-arm64-musl": "4.60.2",
+        "@rollup/rollup-linux-loong64-gnu": "4.60.2",
+        "@rollup/rollup-linux-loong64-musl": "4.60.2",
+        "@rollup/rollup-linux-ppc64-gnu": "4.60.2",
+        "@rollup/rollup-linux-ppc64-musl": "4.60.2",
+        "@rollup/rollup-linux-riscv64-gnu": "4.60.2",
+        "@rollup/rollup-linux-riscv64-musl": "4.60.2",
+        "@rollup/rollup-linux-s390x-gnu": "4.60.2",
+        "@rollup/rollup-linux-x64-gnu": "4.60.2",
+        "@rollup/rollup-linux-x64-musl": "4.60.2",
+        "@rollup/rollup-openbsd-x64": "4.60.2",
+        "@rollup/rollup-openharmony-arm64": "4.60.2",
+        "@rollup/rollup-win32-arm64-msvc": "4.60.2",
+        "@rollup/rollup-win32-ia32-msvc": "4.60.2",
+        "@rollup/rollup-win32-x64-gnu": "4.60.2",
+        "@rollup/rollup-win32-x64-msvc": "4.60.2",
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/rollup-plugin-visualizer": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-7.0.1.tgz",
+      "integrity": "sha512-UJUT4+1Ho4OcWmPYU3sYXgUqI8B8Ayfe06MX7y0qCJ1K8aGoKtR/NDd/2nZqM7ADkrzny+I99Ul7GgyoiVNAgg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "open": "^11.0.0",
+        "picomatch": "^4.0.2",
+        "source-map": "^0.7.4",
+        "yargs": "^18.0.0"
+      },
+      "bin": {
+        "rollup-plugin-visualizer": "dist/bin/cli.js"
+      },
+      "engines": {
+        "node": ">=22"
+      },
+      "peerDependencies": {
+        "rolldown": "1.x || ^1.0.0-beta || ^1.0.0-rc",
+        "rollup": "2.x || 3.x || 4.x"
+      },
+      "peerDependenciesMeta": {
+        "rolldown": {
+          "optional": true
+        },
+        "rollup": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/rou3": {
+      "version": "0.8.1",
+      "resolved": "https://registry.npmjs.org/rou3/-/rou3-0.8.1.tgz",
+      "integrity": "sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/run-applescript": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz",
+      "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/sax": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/sax/-/sax-1.5.0.tgz",
+      "integrity": "sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==",
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": ">=11.0.0"
+      }
+    },
+    "node_modules/scheduler": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
+      "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
+      "license": "MIT"
+    },
+    "node_modules/scule": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz",
+      "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/semver": {
+      "version": "7.7.4",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+      "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/send": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz",
+      "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "debug": "^4.4.3",
+        "encodeurl": "^2.0.0",
+        "escape-html": "^1.0.3",
+        "etag": "^1.8.1",
+        "fresh": "^2.0.0",
+        "http-errors": "^2.0.1",
+        "mime-types": "^3.0.2",
+        "ms": "^2.1.3",
+        "on-finished": "^2.4.1",
+        "range-parser": "^1.2.1",
+        "statuses": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/serialize-javascript": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.5.tgz",
+      "integrity": "sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==",
+      "license": "BSD-3-Clause",
+      "peer": true,
+      "engines": {
+        "node": ">=20.0.0"
+      }
+    },
+    "node_modules/seroval": {
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.5.2.tgz",
+      "integrity": "sha512-xcRN39BdsnO9Tf+VzsE7b3JyTJASItIV1FVFewJKCFcW4s4haIKS3e6vj8PGB9qBwC7tnuOywQMdv5N4qkzi7Q==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/serve-placeholder": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/serve-placeholder/-/serve-placeholder-2.0.2.tgz",
+      "integrity": "sha512-/TMG8SboeiQbZJWRlfTCqMs2DD3SZgWp0kDQePz9yUuCnDfDh/92gf7/PxGhzXTKBIPASIHxFcZndoNbp6QOLQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "defu": "^6.1.4"
+      }
+    },
+    "node_modules/serve-static": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz",
+      "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "encodeurl": "^2.0.0",
+        "escape-html": "^1.0.3",
+        "parseurl": "^1.3.3",
+        "send": "^1.2.0"
+      },
+      "engines": {
+        "node": ">= 18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/setprototypeof": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+      "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+      "license": "ISC",
+      "peer": true
+    },
+    "node_modules/sharp": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
+      "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@img/colour": "^1.0.0",
+        "detect-libc": "^2.1.2",
+        "semver": "^7.7.3"
+      },
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-darwin-arm64": "0.34.5",
+        "@img/sharp-darwin-x64": "0.34.5",
+        "@img/sharp-libvips-darwin-arm64": "1.2.4",
+        "@img/sharp-libvips-darwin-x64": "1.2.4",
+        "@img/sharp-libvips-linux-arm": "1.2.4",
+        "@img/sharp-libvips-linux-arm64": "1.2.4",
+        "@img/sharp-libvips-linux-ppc64": "1.2.4",
+        "@img/sharp-libvips-linux-riscv64": "1.2.4",
+        "@img/sharp-libvips-linux-s390x": "1.2.4",
+        "@img/sharp-libvips-linux-x64": "1.2.4",
+        "@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
+        "@img/sharp-libvips-linuxmusl-x64": "1.2.4",
+        "@img/sharp-linux-arm": "0.34.5",
+        "@img/sharp-linux-arm64": "0.34.5",
+        "@img/sharp-linux-ppc64": "0.34.5",
+        "@img/sharp-linux-riscv64": "0.34.5",
+        "@img/sharp-linux-s390x": "0.34.5",
+        "@img/sharp-linux-x64": "0.34.5",
+        "@img/sharp-linuxmusl-arm64": "0.34.5",
+        "@img/sharp-linuxmusl-x64": "0.34.5",
+        "@img/sharp-wasm32": "0.34.5",
+        "@img/sharp-win32-arm64": "0.34.5",
+        "@img/sharp-win32-ia32": "0.34.5",
+        "@img/sharp-win32-x64": "0.34.5"
+      }
+    },
+    "node_modules/shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "shebang-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shell-quote": {
+      "version": "1.8.3",
+      "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
+      "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/shiki": {
+      "version": "3.23.0",
+      "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.23.0.tgz",
+      "integrity": "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==",
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/core": "3.23.0",
+        "@shikijs/engine-javascript": "3.23.0",
+        "@shikijs/engine-oniguruma": "3.23.0",
+        "@shikijs/langs": "3.23.0",
+        "@shikijs/themes": "3.23.0",
+        "@shikijs/types": "3.23.0",
+        "@shikijs/vscode-textmate": "^10.0.2",
+        "@types/hast": "^3.0.4"
+      }
+    },
+    "node_modules/signal-exit": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+      "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+      "license": "ISC",
+      "peer": true,
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/simple-git": {
+      "version": "3.36.0",
+      "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.36.0.tgz",
+      "integrity": "sha512-cGQjLjK8bxJw4QuYT7gxHw3/IouVESbhahSsHrX97MzCL1gu2u7oy38W6L2ZIGECEfIBG4BabsWDPjBxJENv9Q==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@kwsites/file-exists": "^1.1.1",
+        "@kwsites/promise-deferred": "^1.1.1",
+        "@simple-git/args-pathspec": "^1.0.3",
+        "@simple-git/argv-parser": "^1.1.0",
+        "debug": "^4.4.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/steveukx/git-js?sponsor=1"
+      }
+    },
+    "node_modules/sirv": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
+      "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@polka/url": "^1.0.0-next.24",
+        "mrmime": "^2.0.0",
+        "totalist": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/sisteransi": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
+      "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
+      "license": "MIT"
+    },
+    "node_modules/sitemap": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-9.0.1.tgz",
+      "integrity": "sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "^24.9.2",
+        "@types/sax": "^1.2.1",
+        "arg": "^5.0.0",
+        "sax": "^1.4.1"
+      },
+      "bin": {
+        "sitemap": "dist/esm/cli.js"
+      },
+      "engines": {
+        "node": ">=20.19.5",
+        "npm": ">=10.8.2"
+      }
+    },
+    "node_modules/slash": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz",
+      "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/smob": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/smob/-/smob-1.6.1.tgz",
+      "integrity": "sha512-KAkBqZl3c2GvNgNhcoyJae1aKldDW0LO279wF9bk1PnluRTETKBq0WyzRXxEhoQLk56yHaOY4JCBEKDuJIET5g==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=20.0.0"
+      }
+    },
+    "node_modules/smol-toml": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.1.tgz",
+      "integrity": "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==",
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">= 18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/cyyynthia"
+      }
+    },
+    "node_modules/source-map": {
+      "version": "0.7.6",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
+      "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">= 12"
+      }
+    },
+    "node_modules/source-map-js": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+      "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-support": {
+      "version": "0.5.21",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+      "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
+    "node_modules/source-map-support/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "license": "BSD-3-Clause",
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/space-separated-tokens": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz",
+      "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/srvx": {
+      "version": "0.11.15",
+      "resolved": "https://registry.npmjs.org/srvx/-/srvx-0.11.15.tgz",
+      "integrity": "sha512-iXsux0UcOjdvs0LCMa2Ws3WwcDUozA3JN3BquNXkaFPP7TpRqgunKdEgoZ/uwb1J6xaYHfxtz9Twlh6yzwM6Tg==",
+      "license": "MIT",
+      "peer": true,
+      "bin": {
+        "srvx": "bin/srvx.mjs"
+      },
+      "engines": {
+        "node": ">=20.16.0"
+      }
+    },
+    "node_modules/standard-as-callback": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
+      "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/starlight-llms-txt": {
+      "version": "0.8.1",
+      "resolved": "https://registry.npmjs.org/starlight-llms-txt/-/starlight-llms-txt-0.8.1.tgz",
+      "integrity": "sha512-bRMck9OGNiKXyeJzA6Qy2N/gqC40aERpucOOagl+dPz5s/XeY+9p5dx4wBk3Qiicy3dF/F62Zt9iPPff/POpvA==",
+      "license": "MIT",
+      "dependencies": {
+        "@astrojs/mdx": "^5.0.3",
+        "@types/hast": "^3.0.4",
+        "@types/micromatch": "^4.0.10",
+        "github-slugger": "^2.0.0",
+        "hast-util-select": "^6.0.4",
+        "micromatch": "^4.0.8",
+        "rehype-parse": "^9.0.1",
+        "rehype-remark": "^10.0.1",
+        "remark-gfm": "^4.0.1",
+        "remark-stringify": "^11.0.0",
+        "unified": "^11.0.5",
+        "unist-util-remove": "^4.0.0"
+      },
+      "peerDependencies": {
+        "@astrojs/starlight": ">=0.38.0",
+        "astro": "^6.0.0"
+      }
+    },
+    "node_modules/starlight-sidebar-topics": {
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/starlight-sidebar-topics/-/starlight-sidebar-topics-0.7.1.tgz",
+      "integrity": "sha512-2PBR05ZUvnKNoJtbL2u6GoE1qmQD0tFcd5+inYEJHJkx3LE2P+vlNslofTGHLtzch2XzyNbHUBQQu35bouA6NQ==",
+      "license": "MIT",
+      "dependencies": {
+        "picomatch": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=22.12.0"
+      },
+      "peerDependencies": {
+        "@astrojs/starlight": ">=0.38.0"
+      }
+    },
+    "node_modules/statuses": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+      "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/std-env": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz",
+      "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/stream-replace-string": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/stream-replace-string/-/stream-replace-string-2.0.0.tgz",
+      "integrity": "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==",
+      "license": "MIT"
+    },
+    "node_modules/streamx": {
+      "version": "2.25.0",
+      "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz",
+      "integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "events-universal": "^1.0.0",
+        "fast-fifo": "^1.3.2",
+        "text-decoder": "^1.1.0"
+      }
+    },
+    "node_modules/string_decoder": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "safe-buffer": "~5.2.0"
+      }
+    },
+    "node_modules/string-width": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+      "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "eastasianwidth": "^0.2.0",
+        "emoji-regex": "^9.2.2",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/string-width-cjs": {
+      "name": "string-width",
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/string-width-cjs/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/string-width-cjs/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/string-width-cjs/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/stringify-entities": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz",
+      "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==",
+      "license": "MIT",
+      "dependencies": {
+        "character-entities-html4": "^2.0.0",
+        "character-entities-legacy": "^3.0.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
+      "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "ansi-regex": "^6.2.2"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+      }
+    },
+    "node_modules/strip-ansi-cjs": {
+      "name": "strip-ansi",
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-final-newline": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
+      "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/strip-literal": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz",
+      "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "js-tokens": "^9.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/strip-literal/node_modules/js-tokens": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
+      "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/strnum": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.3.tgz",
+      "integrity": "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/NaturalIntelligence"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/structured-clone-es": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/structured-clone-es/-/structured-clone-es-2.0.0.tgz",
+      "integrity": "sha512-5UuAHmBLXYPCl22xWJrFuGmIhBKQzxISPVz6E7nmTmTcAOpUzlbjKJsRrCE4vADmMQ0dzeCnlWn9XufnAGf76Q==",
+      "license": "ISC",
+      "peer": true
+    },
+    "node_modules/style-to-js": {
+      "version": "1.1.21",
+      "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz",
+      "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==",
+      "license": "MIT",
+      "dependencies": {
+        "style-to-object": "1.0.14"
+      }
+    },
+    "node_modules/style-to-object": {
+      "version": "1.0.14",
+      "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz",
+      "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==",
+      "license": "MIT",
+      "dependencies": {
+        "inline-style-parser": "0.2.7"
+      }
+    },
+    "node_modules/stylehacks": {
+      "version": "7.0.10",
+      "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-7.0.10.tgz",
+      "integrity": "sha512-sRJ7klmhe/Fl5woJcbJUa2qP1Ueffsl1CQI4ePvqXLkZmcIuAt09aP9uT/FOFPqXh9Rh8M5UkgEnwTdTKn/Aag==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "browserslist": "^4.28.2",
+        "postcss-selector-parser": "^7.1.1"
+      },
+      "engines": {
+        "node": "^18.12.0 || ^20.9.0 || >=22.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.5.10"
+      }
+    },
+    "node_modules/stylehacks/node_modules/postcss-selector-parser": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz",
+      "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "10.2.2",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz",
+      "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/supports-color?sponsor=1"
+      }
+    },
+    "node_modules/supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/svgo": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz",
+      "integrity": "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==",
+      "license": "MIT",
+      "dependencies": {
+        "commander": "^11.1.0",
+        "css-select": "^5.1.0",
+        "css-tree": "^3.0.1",
+        "css-what": "^6.1.0",
+        "csso": "^5.0.5",
+        "picocolors": "^1.1.1",
+        "sax": "^1.5.0"
+      },
+      "bin": {
+        "svgo": "bin/svgo.js"
+      },
+      "engines": {
+        "node": ">=16"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/svgo"
+      }
+    },
+    "node_modules/svgo/node_modules/commander": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
+      "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/tagged-tag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz",
+      "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/tar": {
+      "version": "7.5.11",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.11.tgz",
+      "integrity": "sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ==",
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "@isaacs/fs-minipass": "^4.0.0",
+        "chownr": "^3.0.0",
+        "minipass": "^7.1.2",
+        "minizlib": "^3.1.0",
+        "yallist": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tar-stream": {
+      "version": "3.1.8",
+      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.8.tgz",
+      "integrity": "sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "b4a": "^1.6.4",
+        "bare-fs": "^4.5.5",
+        "fast-fifo": "^1.2.0",
+        "streamx": "^2.15.0"
+      }
+    },
+    "node_modules/teex": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz",
+      "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "streamx": "^2.12.5"
+      }
+    },
+    "node_modules/terser": {
+      "version": "5.46.1",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.1.tgz",
+      "integrity": "sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==",
+      "license": "BSD-2-Clause",
+      "peer": true,
+      "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"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/terser/node_modules/commander": {
+      "version": "2.20.3",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/text-decoder": {
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz",
+      "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "dependencies": {
+        "b4a": "^1.6.4"
+      }
+    },
+    "node_modules/tiny-inflate": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
+      "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==",
+      "license": "MIT"
+    },
+    "node_modules/tiny-invariant": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
+      "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/tinyclip": {
+      "version": "0.1.12",
+      "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-0.1.12.tgz",
+      "integrity": "sha512-Ae3OVUqifDw0wBriIBS7yVaW44Dp6eSHQcyq4Igc7eN2TJH/2YsicswaW+J/OuMvhpDPOKEgpAZCjkb4hpoyeA==",
+      "license": "MIT",
+      "engines": {
+        "node": "^16.14.0 || >= 17.3.0"
+      }
+    },
+    "node_modules/tinyexec": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz",
+      "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tinyglobby": {
+      "version": "0.2.16",
+      "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
+      "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
+      "license": "MIT",
+      "dependencies": {
+        "fdir": "^6.5.0",
+        "picomatch": "^4.0.4"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/SuperchupuDev"
+      }
+    },
+    "node_modules/tldts": {
+      "version": "7.0.25",
+      "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.25.tgz",
+      "integrity": "sha512-keinCnPbwXEUG3ilrWQZU+CqcTTzHq9m2HhoUP2l7Xmi8l1LuijAXLpAJ5zRW+ifKTNscs4NdCkfkDCBYm352w==",
+      "license": "MIT",
+      "dependencies": {
+        "tldts-core": "^7.0.25"
+      },
+      "bin": {
+        "tldts": "bin/cli.js"
+      }
+    },
+    "node_modules/tldts-core": {
+      "version": "7.0.25",
+      "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.25.tgz",
+      "integrity": "sha512-ZjCZK0rppSBu7rjHYDYsEaMOIbbT+nWF57hKkv4IUmZWBNrBWBOjIElc0mKRgLM8bm7x/BBlof6t2gi/Oq/Asw==",
+      "license": "MIT"
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "license": "MIT",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/toidentifier": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+      "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/totalist": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
+      "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/tr46": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+      "license": "MIT"
+    },
+    "node_modules/trim-lines": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",
+      "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/trim-trailing-lines": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-2.1.0.tgz",
+      "integrity": "sha512-5UR5Biq4VlVOtzqkm2AZlgvSlDJtME46uV0br0gENbwN4l5+mMKT4b9gJKqWtuL2zAIqajGJGuvbCbcAJUZqBg==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/trough": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz",
+      "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/tsconfck": {
+      "version": "3.1.6",
+      "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz",
+      "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==",
+      "license": "MIT",
+      "bin": {
+        "tsconfck": "bin/tsconfck.js"
+      },
+      "engines": {
+        "node": "^18 || >=20"
+      },
+      "peerDependencies": {
+        "typescript": "^5.0.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/tslib": {
+      "version": "2.8.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+      "license": "0BSD"
+    },
+    "node_modules/turndown": {
+      "version": "7.2.2",
+      "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.2.tgz",
+      "integrity": "sha512-1F7db8BiExOKxjSMU2b7if62D/XOyQyZbPKq/nUwopfgnHlqXHqQ0lvfUTeUIr1lZJzOPFn43dODyMSIfvWRKQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@mixmark-io/domino": "^2.2.0"
+      }
+    },
+    "node_modules/turndown-plugin-gfm": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/turndown-plugin-gfm/-/turndown-plugin-gfm-1.0.2.tgz",
+      "integrity": "sha512-vwz9tfvF7XN/jE0dGoBei3FXWuvll78ohzCZQuOb+ZjWrs3a0XhQVomJEb2Qh4VHTPNRO4GPZh0V7VRbiWwkRg==",
+      "license": "MIT"
+    },
+    "node_modules/type-fest": {
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.6.0.tgz",
+      "integrity": "sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA==",
+      "license": "(MIT OR CC0-1.0)",
+      "peer": true,
+      "dependencies": {
+        "tagged-tag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/type-level-regexp": {
+      "version": "0.1.17",
+      "resolved": "https://registry.npmjs.org/type-level-regexp/-/type-level-regexp-0.1.17.tgz",
+      "integrity": "sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/typesafe-path": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/typesafe-path/-/typesafe-path-0.2.2.tgz",
+      "integrity": "sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/typescript": {
+      "version": "5.9.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+      "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+      "license": "Apache-2.0",
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "node_modules/typescript-auto-import-cache": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/typescript-auto-import-cache/-/typescript-auto-import-cache-0.3.6.tgz",
+      "integrity": "sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "semver": "^7.3.8"
+      }
+    },
+    "node_modules/ufo": {
+      "version": "1.6.3",
+      "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz",
+      "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==",
+      "license": "MIT"
+    },
+    "node_modules/uhyphen": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/uhyphen/-/uhyphen-0.2.0.tgz",
+      "integrity": "sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==",
+      "license": "ISC"
+    },
+    "node_modules/ultrahtml": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.6.0.tgz",
+      "integrity": "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==",
+      "license": "MIT"
+    },
+    "node_modules/uncrypto": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz",
+      "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==",
+      "license": "MIT"
+    },
+    "node_modules/unctx": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/unctx/-/unctx-2.5.0.tgz",
+      "integrity": "sha512-p+Rz9x0R7X+CYDkT+Xg8/GhpcShTlU8n+cf9OtOEf7zEQsNcCZO1dPKNRDqvUTaq+P32PMMkxWHwfrxkqfqAYg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "acorn": "^8.15.0",
+        "estree-walker": "^3.0.3",
+        "magic-string": "^0.30.21",
+        "unplugin": "^2.3.11"
+      }
+    },
+    "node_modules/unctx/node_modules/unplugin": {
+      "version": "2.3.11",
+      "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz",
+      "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@jridgewell/remapping": "^2.3.5",
+        "acorn": "^8.15.0",
+        "picomatch": "^4.0.3",
+        "webpack-virtual-modules": "^0.6.2"
+      },
+      "engines": {
+        "node": ">=18.12.0"
+      }
+    },
+    "node_modules/undici-types": {
+      "version": "7.16.0",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
+      "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
+      "license": "MIT"
+    },
+    "node_modules/unenv": {
+      "version": "2.0.0-rc.24",
+      "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz",
+      "integrity": "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "pathe": "^2.0.3"
+      }
+    },
+    "node_modules/unhead": {
+      "version": "2.1.13",
+      "resolved": "https://registry.npmjs.org/unhead/-/unhead-2.1.13.tgz",
+      "integrity": "sha512-jO9M1sI6b2h/1KpIu4Jeu+ptumLmUKboRRLxys5pYHFeT+lqTzfNHbYUX9bxVDhC1FBszAGuWcUVlmvIPsah8Q==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "hookable": "^6.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/harlan-zw"
+      }
+    },
+    "node_modules/unicorn-magic": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz",
+      "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/unified": {
+      "version": "11.0.5",
+      "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
+      "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "^3.0.0",
+        "bail": "^2.0.0",
+        "devlop": "^1.0.0",
+        "extend": "^3.0.0",
+        "is-plain-obj": "^4.0.0",
+        "trough": "^2.0.0",
+        "vfile": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unifont": {
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.4.tgz",
+      "integrity": "sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==",
+      "license": "MIT",
+      "dependencies": {
+        "css-tree": "^3.1.0",
+        "ofetch": "^1.5.1",
+        "ohash": "^2.0.11"
+      }
+    },
+    "node_modules/unimport": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/unimport/-/unimport-6.1.0.tgz",
+      "integrity": "sha512-ocgNKyiqj7Hw7oHt7A7D3za3fq28eShe1EloL6hsoQgn7CF51Y4CqFT9ISG3rEy0JpA8CCz/sY5h5OovOn62VQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "acorn": "^8.16.0",
+        "escape-string-regexp": "^5.0.0",
+        "estree-walker": "^3.0.3",
+        "local-pkg": "^1.1.2",
+        "magic-string": "^0.30.21",
+        "mlly": "^1.8.2",
+        "pathe": "^2.0.3",
+        "picomatch": "^4.0.4",
+        "pkg-types": "^2.3.0",
+        "scule": "^1.3.0",
+        "strip-literal": "^3.1.0",
+        "tinyglobby": "^0.2.16",
+        "unplugin": "^3.0.0",
+        "unplugin-utils": "^0.3.1"
+      },
+      "engines": {
+        "node": ">=18.12.0"
+      }
+    },
+    "node_modules/unist-util-find-after": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz",
+      "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "^3.0.0",
+        "unist-util-is": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-is": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz",
+      "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-modify-children": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-4.0.0.tgz",
+      "integrity": "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "^3.0.0",
+        "array-iterate": "^2.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-position": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz",
+      "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-position-from-estree": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz",
+      "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-remove": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-4.0.0.tgz",
+      "integrity": "sha512-b4gokeGId57UVRX/eVKej5gXqGlc9+trkORhFJpu9raqZkZhU0zm8Doi05+HaiBsMEIJowL+2WtQ5ItjsngPXg==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "^3.0.0",
+        "unist-util-is": "^6.0.0",
+        "unist-util-visit-parents": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-remove-position": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz",
+      "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "^3.0.0",
+        "unist-util-visit": "^5.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-stringify-position": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz",
+      "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-visit": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz",
+      "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "^3.0.0",
+        "unist-util-is": "^6.0.0",
+        "unist-util-visit-parents": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-visit-children": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-3.0.0.tgz",
+      "integrity": "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "^3.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unist-util-visit-parents": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz",
+      "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "^3.0.0",
+        "unist-util-is": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/unplugin": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz",
+      "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@jridgewell/remapping": "^2.3.5",
+        "picomatch": "^4.0.3",
+        "webpack-virtual-modules": "^0.6.2"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/unplugin-utils": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.1.tgz",
+      "integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "pathe": "^2.0.3",
+        "picomatch": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=20.19.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sxzz"
+      }
+    },
+    "node_modules/unrouting": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/unrouting/-/unrouting-0.1.7.tgz",
+      "integrity": "sha512-+0hfD+CVWtD636rc5Fn9VEjjTEDhdqgMpbwAuVoUmydSHDaMNiFW93SJG4LV++RoGSEAyvQN5uABAscYpDphpQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "escape-string-regexp": "^5.0.0",
+        "ufo": "^1.6.3"
+      }
+    },
+    "node_modules/unstorage": {
+      "version": "1.17.5",
+      "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.5.tgz",
+      "integrity": "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==",
+      "license": "MIT",
+      "dependencies": {
+        "anymatch": "^3.1.3",
+        "chokidar": "^5.0.0",
+        "destr": "^2.0.5",
+        "h3": "^1.15.10",
+        "lru-cache": "^11.2.7",
+        "node-fetch-native": "^1.6.7",
+        "ofetch": "^1.5.1",
+        "ufo": "^1.6.3"
+      },
+      "peerDependencies": {
+        "@azure/app-configuration": "^1.8.0",
+        "@azure/cosmos": "^4.2.0",
+        "@azure/data-tables": "^13.3.0",
+        "@azure/identity": "^4.6.0",
+        "@azure/keyvault-secrets": "^4.9.0",
+        "@azure/storage-blob": "^12.26.0",
+        "@capacitor/preferences": "^6 || ^7 || ^8",
+        "@deno/kv": ">=0.9.0",
+        "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0",
+        "@planetscale/database": "^1.19.0",
+        "@upstash/redis": "^1.34.3",
+        "@vercel/blob": ">=0.27.1",
+        "@vercel/functions": "^2.2.12 || ^3.0.0",
+        "@vercel/kv": "^1 || ^2 || ^3",
+        "aws4fetch": "^1.0.20",
+        "db0": ">=0.2.1",
+        "idb-keyval": "^6.2.1",
+        "ioredis": "^5.4.2",
+        "uploadthing": "^7.4.4"
+      },
+      "peerDependenciesMeta": {
+        "@azure/app-configuration": {
+          "optional": true
+        },
+        "@azure/cosmos": {
+          "optional": true
+        },
+        "@azure/data-tables": {
+          "optional": true
+        },
+        "@azure/identity": {
+          "optional": true
+        },
+        "@azure/keyvault-secrets": {
+          "optional": true
+        },
+        "@azure/storage-blob": {
+          "optional": true
+        },
+        "@capacitor/preferences": {
+          "optional": true
+        },
+        "@deno/kv": {
+          "optional": true
+        },
+        "@netlify/blobs": {
+          "optional": true
+        },
+        "@planetscale/database": {
+          "optional": true
+        },
+        "@upstash/redis": {
+          "optional": true
+        },
+        "@vercel/blob": {
+          "optional": true
+        },
+        "@vercel/functions": {
+          "optional": true
+        },
+        "@vercel/kv": {
+          "optional": true
+        },
+        "aws4fetch": {
+          "optional": true
+        },
+        "db0": {
+          "optional": true
+        },
+        "idb-keyval": {
+          "optional": true
+        },
+        "ioredis": {
+          "optional": true
+        },
+        "uploadthing": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/untun": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/untun/-/untun-0.1.3.tgz",
+      "integrity": "sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "citty": "^0.1.5",
+        "consola": "^3.2.3",
+        "pathe": "^1.1.1"
+      },
+      "bin": {
+        "untun": "bin/untun.mjs"
+      }
+    },
+    "node_modules/untun/node_modules/citty": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz",
+      "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "consola": "^3.2.3"
+      }
+    },
+    "node_modules/untun/node_modules/pathe": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
+      "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/untyped": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/untyped/-/untyped-2.0.0.tgz",
+      "integrity": "sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "citty": "^0.1.6",
+        "defu": "^6.1.4",
+        "jiti": "^2.4.2",
+        "knitwork": "^1.2.0",
+        "scule": "^1.3.0"
+      },
+      "bin": {
+        "untyped": "dist/cli.mjs"
+      }
+    },
+    "node_modules/untyped/node_modules/citty": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz",
+      "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "consola": "^3.2.3"
+      }
+    },
+    "node_modules/unwasm": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/unwasm/-/unwasm-0.5.3.tgz",
+      "integrity": "sha512-keBgTSfp3r6+s9ZcSma+0chwxQdmLbB5+dAD9vjtB21UTMYuKAxHXCU1K2CbCtnP09EaWeRvACnXk0EJtUx+hw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "exsolve": "^1.0.8",
+        "knitwork": "^1.3.0",
+        "magic-string": "^0.30.21",
+        "mlly": "^1.8.0",
+        "pathe": "^2.0.3",
+        "pkg-types": "^2.3.0"
+      }
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+      "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "escalade": "^3.2.0",
+        "picocolors": "^1.1.1"
+      },
+      "bin": {
+        "update-browserslist-db": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/uqr": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/uqr/-/uqr-0.1.3.tgz",
+      "integrity": "sha512-0rjE8iEJe4YmT9TOhwsZtqCMRLc5DXZUI2UEYUUg63ikBkqqE5EYWaI0etFe/5KUcmcYwLih2RND1kq+hrUJXA==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/uri-js": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+      "license": "BSD-2-Clause",
+      "optional": true,
+      "dependencies": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "node_modules/use-callback-ref": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
+      "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/use-sidecar": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
+      "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
+      "license": "MIT",
+      "dependencies": {
+        "detect-node-es": "^1.1.0",
+        "tslib": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+      "license": "MIT"
+    },
+    "node_modules/vfile": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",
+      "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "^3.0.0",
+        "vfile-message": "^4.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/vfile-location": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz",
+      "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "^3.0.0",
+        "vfile": "^6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/vfile-message": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz",
+      "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "^3.0.0",
+        "unist-util-stringify-position": "^4.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
+      }
+    },
+    "node_modules/vite": {
+      "version": "7.3.2",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz",
+      "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==",
+      "license": "MIT",
+      "dependencies": {
+        "esbuild": "^0.27.0",
+        "fdir": "^6.5.0",
+        "picomatch": "^4.0.3",
+        "postcss": "^8.5.6",
+        "rollup": "^4.43.0",
+        "tinyglobby": "^0.2.15"
+      },
+      "bin": {
+        "vite": "bin/vite.js"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "funding": {
+        "url": "https://github.com/vitejs/vite?sponsor=1"
+      },
+      "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"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "jiti": {
+          "optional": true
+        },
+        "less": {
+          "optional": true
+        },
+        "lightningcss": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "sass-embedded": {
+          "optional": true
+        },
+        "stylus": {
+          "optional": true
+        },
+        "sugarss": {
+          "optional": true
+        },
+        "terser": {
+          "optional": true
+        },
+        "tsx": {
+          "optional": true
+        },
+        "yaml": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vite-dev-rpc": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/vite-dev-rpc/-/vite-dev-rpc-1.1.0.tgz",
+      "integrity": "sha512-pKXZlgoXGoE8sEKiKJSng4hI1sQ4wi5YT24FCrwrLt6opmkjlqPPVmiPWWJn8M8byMxRGzp1CrFuqQs4M/Z39A==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "birpc": "^2.4.0",
+        "vite-hot-client": "^2.1.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0"
+      }
+    },
+    "node_modules/vite-dev-rpc/node_modules/birpc": {
+      "version": "2.9.0",
+      "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz",
+      "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==",
+      "license": "MIT",
+      "peer": true,
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/vite-hot-client": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/vite-hot-client/-/vite-hot-client-2.1.0.tgz",
+      "integrity": "sha512-7SpgZmU7R+dDnSmvXE1mfDtnHLHQSisdySVR7lO8ceAXvM0otZeuQQ6C8LrS5d/aYyP/QZ0hI0L+dIPrm4YlFQ==",
+      "license": "MIT",
+      "peer": true,
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "vite": "^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0"
+      }
+    },
+    "node_modules/vite-node": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-5.3.0.tgz",
+      "integrity": "sha512-8f20COPYJujc3OKPX6OuyBy3ZIv2det4eRRU4GY1y2MjbeGSUmPjedxg1b72KnTagCofwvZ65ThzjxDW2AtQFQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "cac": "^6.7.14",
+        "es-module-lexer": "^2.0.0",
+        "obug": "^2.1.1",
+        "pathe": "^2.0.3",
+        "vite": "^7.3.1"
+      },
+      "bin": {
+        "vite-node": "dist/cli.mjs"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/antfu"
+      }
+    },
+    "node_modules/vite-plugin-checker": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/vite-plugin-checker/-/vite-plugin-checker-0.12.0.tgz",
+      "integrity": "sha512-CmdZdDOGss7kdQwv73UyVgLPv0FVYe5czAgnmRX2oKljgEvSrODGuClaV3PDR2+3ou7N/OKGauDDBjy2MB07Rg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.27.1",
+        "chokidar": "^4.0.3",
+        "npm-run-path": "^6.0.0",
+        "picocolors": "^1.1.1",
+        "picomatch": "^4.0.3",
+        "tiny-invariant": "^1.3.3",
+        "tinyglobby": "^0.2.15",
+        "vscode-uri": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=16.11"
+      },
+      "peerDependencies": {
+        "@biomejs/biome": ">=1.7",
+        "eslint": ">=9.39.1",
+        "meow": "^13.2.0",
+        "optionator": "^0.9.4",
+        "oxlint": ">=1",
+        "stylelint": ">=16",
+        "typescript": "*",
+        "vite": ">=5.4.21",
+        "vls": "*",
+        "vti": "*",
+        "vue-tsc": "~2.2.10 || ^3.0.0"
+      },
+      "peerDependenciesMeta": {
+        "@biomejs/biome": {
+          "optional": true
+        },
+        "eslint": {
+          "optional": true
+        },
+        "meow": {
+          "optional": true
+        },
+        "optionator": {
+          "optional": true
+        },
+        "oxlint": {
+          "optional": true
+        },
+        "stylelint": {
+          "optional": true
+        },
+        "typescript": {
+          "optional": true
+        },
+        "vls": {
+          "optional": true
+        },
+        "vti": {
+          "optional": true
+        },
+        "vue-tsc": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vite-plugin-checker/node_modules/chokidar": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+      "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/vite-plugin-checker/node_modules/npm-run-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz",
+      "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "path-key": "^4.0.0",
+        "unicorn-magic": "^0.3.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/vite-plugin-checker/node_modules/path-key": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
+      "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/vite-plugin-checker/node_modules/readdirp": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+      "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">= 14.18.0"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/vite-plugin-checker/node_modules/unicorn-magic": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
+      "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/vite-plugin-inspect": {
+      "version": "11.3.3",
+      "resolved": "https://registry.npmjs.org/vite-plugin-inspect/-/vite-plugin-inspect-11.3.3.tgz",
+      "integrity": "sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "ansis": "^4.1.0",
+        "debug": "^4.4.1",
+        "error-stack-parser-es": "^1.0.5",
+        "ohash": "^2.0.11",
+        "open": "^10.2.0",
+        "perfect-debounce": "^2.0.0",
+        "sirv": "^3.0.1",
+        "unplugin-utils": "^0.3.0",
+        "vite-dev-rpc": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "vite": "^6.0.0 || ^7.0.0-0"
+      },
+      "peerDependenciesMeta": {
+        "@nuxt/kit": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vite-plugin-inspect/node_modules/open": {
+      "version": "10.2.0",
+      "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz",
+      "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "default-browser": "^5.2.1",
+        "define-lazy-prop": "^3.0.0",
+        "is-inside-container": "^1.0.0",
+        "wsl-utils": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/vite-plugin-inspect/node_modules/wsl-utils": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz",
+      "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "is-wsl": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/vite-plugin-vue-tracer": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/vite-plugin-vue-tracer/-/vite-plugin-vue-tracer-1.3.0.tgz",
+      "integrity": "sha512-Cgfce6VikzOw5MUJTpeg50s5rRjzU1Vr61ZjuHunVVHLjZZ5AUlgyExHthZ3r59vtoz9W2rDt23FYG81avYBKw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "estree-walker": "^3.0.3",
+        "exsolve": "^1.0.8",
+        "magic-string": "^0.30.21",
+        "pathe": "^2.0.3",
+        "source-map-js": "^1.2.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "vite": "^6.0.0 || ^7.0.0",
+        "vue": "^3.5.0"
+      }
+    },
+    "node_modules/vitefu": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.2.tgz",
+      "integrity": "sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==",
+      "license": "MIT",
+      "workspaces": [
+        "tests/deps/*",
+        "tests/projects/*",
+        "tests/projects/workspace/packages/*"
+      ],
+      "peerDependencies": {
+        "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0"
+      },
+      "peerDependenciesMeta": {
+        "vite": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/volar-service-css": {
+      "version": "0.0.70",
+      "resolved": "https://registry.npmjs.org/volar-service-css/-/volar-service-css-0.0.70.tgz",
+      "integrity": "sha512-K1qyOvBpE3rzdAv3e4/6Rv5yizrYPy5R/ne3IWCAzLBuMO4qBMV3kSqWzj6KUVe6S0AnN6wxF7cRkiaKfYMYJw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "vscode-css-languageservice": "^6.3.0",
+        "vscode-languageserver-textdocument": "^1.0.11",
+        "vscode-uri": "^3.0.8"
+      },
+      "peerDependencies": {
+        "@volar/language-service": "~2.4.0"
+      },
+      "peerDependenciesMeta": {
+        "@volar/language-service": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/volar-service-emmet": {
+      "version": "0.0.70",
+      "resolved": "https://registry.npmjs.org/volar-service-emmet/-/volar-service-emmet-0.0.70.tgz",
+      "integrity": "sha512-xi5bC4m/VyE3zy/n2CXspKeDZs3qA41tHLTw275/7dNWM/RqE2z3BnDICQybHIVp/6G1iOQj5c1qXMgQC08TNg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@emmetio/css-parser": "^0.4.1",
+        "@emmetio/html-matcher": "^1.3.0",
+        "@vscode/emmet-helper": "^2.9.3",
+        "vscode-uri": "^3.0.8"
+      },
+      "peerDependencies": {
+        "@volar/language-service": "~2.4.0"
+      },
+      "peerDependenciesMeta": {
+        "@volar/language-service": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/volar-service-html": {
+      "version": "0.0.70",
+      "resolved": "https://registry.npmjs.org/volar-service-html/-/volar-service-html-0.0.70.tgz",
+      "integrity": "sha512-eR6vCgMdmYAo4n+gcT7DSyBQbwB8S3HZZvSagTf0sxNaD4WppMCFfpqWnkrlGStPKMZvMiejRRVmqsX9dYcTvQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "vscode-html-languageservice": "^5.3.0",
+        "vscode-languageserver-textdocument": "^1.0.11",
+        "vscode-uri": "^3.0.8"
+      },
+      "peerDependencies": {
+        "@volar/language-service": "~2.4.0"
+      },
+      "peerDependenciesMeta": {
+        "@volar/language-service": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/volar-service-prettier": {
+      "version": "0.0.70",
+      "resolved": "https://registry.npmjs.org/volar-service-prettier/-/volar-service-prettier-0.0.70.tgz",
+      "integrity": "sha512-Z6BCFSpGVCd8BPAsZ785Kce1BGlWd5ODqmqZGVuB14MJvrR4+CYz6cDy4F+igmE1gMifqfvMhdgT8Aud4M5ngg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "vscode-uri": "^3.0.8"
+      },
+      "peerDependencies": {
+        "@volar/language-service": "~2.4.0",
+        "prettier": "^2.2 || ^3.0"
+      },
+      "peerDependenciesMeta": {
+        "@volar/language-service": {
+          "optional": true
+        },
+        "prettier": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/volar-service-typescript": {
+      "version": "0.0.70",
+      "resolved": "https://registry.npmjs.org/volar-service-typescript/-/volar-service-typescript-0.0.70.tgz",
+      "integrity": "sha512-l46Bx4cokkUedTd74ojO5H/zqHZJ8SUuyZ0IB8JN4jfRqUM3bQFBHoOwlZCyZmOeO0A3RQNkMnFclxO4c++gsg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "path-browserify": "^1.0.1",
+        "semver": "^7.6.2",
+        "typescript-auto-import-cache": "^0.3.5",
+        "vscode-languageserver-textdocument": "^1.0.11",
+        "vscode-nls": "^5.2.0",
+        "vscode-uri": "^3.0.8"
+      },
+      "peerDependencies": {
+        "@volar/language-service": "~2.4.0"
+      },
+      "peerDependenciesMeta": {
+        "@volar/language-service": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/volar-service-typescript-twoslash-queries": {
+      "version": "0.0.70",
+      "resolved": "https://registry.npmjs.org/volar-service-typescript-twoslash-queries/-/volar-service-typescript-twoslash-queries-0.0.70.tgz",
+      "integrity": "sha512-IdD13Z9N2Bu8EM6CM0fDV1E69olEYGHDU25X51YXmq8Y0CmJ2LNj6gOiBJgpS5JGUqFzECVhMNBW7R0sPdRTMQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "vscode-uri": "^3.0.8"
+      },
+      "peerDependencies": {
+        "@volar/language-service": "~2.4.0"
+      },
+      "peerDependenciesMeta": {
+        "@volar/language-service": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/volar-service-yaml": {
+      "version": "0.0.70",
+      "resolved": "https://registry.npmjs.org/volar-service-yaml/-/volar-service-yaml-0.0.70.tgz",
+      "integrity": "sha512-0c8bXDBeoATF9F6iPIlOuYTuZAC4c+yi0siQo920u7eiBJk8oQmUmg9cDUbR4+Gl++bvGP4plj3fErbJuPqdcQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "vscode-uri": "^3.0.8",
+        "yaml-language-server": "~1.20.0"
+      },
+      "peerDependencies": {
+        "@volar/language-service": "~2.4.0"
+      },
+      "peerDependenciesMeta": {
+        "@volar/language-service": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vscode-css-languageservice": {
+      "version": "6.3.10",
+      "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-6.3.10.tgz",
+      "integrity": "sha512-eq5N9Er3fC4vA9zd9EFhyBG90wtCCuXgRSpAndaOgXMh1Wgep5lBgRIeDgjZBW9pa+332yC9+49cZMW8jcL3MA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vscode/l10n": "^0.0.18",
+        "vscode-languageserver-textdocument": "^1.0.12",
+        "vscode-languageserver-types": "3.17.5",
+        "vscode-uri": "^3.1.0"
+      }
+    },
+    "node_modules/vscode-html-languageservice": {
+      "version": "5.6.2",
+      "resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-5.6.2.tgz",
+      "integrity": "sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vscode/l10n": "^0.0.18",
+        "vscode-languageserver-textdocument": "^1.0.12",
+        "vscode-languageserver-types": "^3.17.5",
+        "vscode-uri": "^3.1.0"
+      }
+    },
+    "node_modules/vscode-json-languageservice": {
+      "version": "4.1.8",
+      "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.1.8.tgz",
+      "integrity": "sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "jsonc-parser": "^3.0.0",
+        "vscode-languageserver-textdocument": "^1.0.1",
+        "vscode-languageserver-types": "^3.16.0",
+        "vscode-nls": "^5.0.0",
+        "vscode-uri": "^3.0.2"
+      },
+      "engines": {
+        "npm": ">=7.0.0"
+      }
+    },
+    "node_modules/vscode-json-languageservice/node_modules/jsonc-parser": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz",
+      "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/vscode-jsonrpc": {
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz",
+      "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/vscode-languageserver": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz",
+      "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "vscode-languageserver-protocol": "3.17.5"
+      },
+      "bin": {
+        "installServerIntoExtension": "bin/installServerIntoExtension"
+      }
+    },
+    "node_modules/vscode-languageserver-protocol": {
+      "version": "3.17.5",
+      "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz",
+      "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "vscode-jsonrpc": "8.2.0",
+        "vscode-languageserver-types": "3.17.5"
+      }
+    },
+    "node_modules/vscode-languageserver-textdocument": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz",
+      "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/vscode-languageserver-types": {
+      "version": "3.17.5",
+      "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz",
+      "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/vscode-nls": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz",
+      "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/vscode-uri": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz",
+      "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==",
+      "license": "MIT"
+    },
+    "node_modules/vue": {
+      "version": "3.5.32",
+      "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.32.tgz",
+      "integrity": "sha512-vM4z4Q9tTafVfMAK7IVzmxg34rSzTFMyIe0UUEijUCkn9+23lj0WRfA83dg7eQZIUlgOSGrkViIaCfqSAUXsMw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@vue/compiler-dom": "3.5.32",
+        "@vue/compiler-sfc": "3.5.32",
+        "@vue/runtime-dom": "3.5.32",
+        "@vue/server-renderer": "3.5.32",
+        "@vue/shared": "3.5.32"
+      },
+      "peerDependencies": {
+        "typescript": "*"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vue-bundle-renderer": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/vue-bundle-renderer/-/vue-bundle-renderer-2.2.0.tgz",
+      "integrity": "sha512-sz/0WEdYH1KfaOm0XaBmRZOWgYTEvUDt6yPYaUzl4E52qzgWLlknaPPTTZmp6benaPTlQAI/hN1x3tAzZygycg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "ufo": "^1.6.1"
+      }
+    },
+    "node_modules/vue-devtools-stub": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/vue-devtools-stub/-/vue-devtools-stub-0.1.0.tgz",
+      "integrity": "sha512-RutnB7X8c5hjq39NceArgXg28WZtZpGc3+J16ljMiYnFhKvd8hITxSWQSQ5bvldxMDU6gG5mkxl1MTQLXckVSQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/vue-router": {
+      "version": "4.6.4",
+      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz",
+      "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==",
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "@vue/devtools-api": "^6.6.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/posva"
+      },
+      "peerDependencies": {
+        "vue": "^3.5.0"
+      }
+    },
+    "node_modules/web-namespaces": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz",
+      "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/webidl-conversions": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/webpack-virtual-modules": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
+      "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/whatwg-url": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+      "license": "MIT",
+      "dependencies": {
+        "tr46": "~0.0.3",
+        "webidl-conversions": "^3.0.0"
+      }
+    },
+    "node_modules/which": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz",
+      "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==",
+      "license": "ISC",
+      "peer": true,
+      "dependencies": {
+        "isexe": "^4.0.0"
+      },
+      "bin": {
+        "node-which": "bin/which.js"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/which-pm-runs": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz",
+      "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/wrap-ansi": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+      "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^6.1.0",
+        "string-width": "^5.0.1",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi-cjs": {
+      "name": "wrap-ansi",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ws": {
+      "version": "8.20.0",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz",
+      "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "peerDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": ">=5.0.2"
+      },
+      "peerDependenciesMeta": {
+        "bufferutil": {
+          "optional": true
+        },
+        "utf-8-validate": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/wsl-utils": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz",
+      "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "is-wsl": "^3.1.0",
+        "powershell-utils": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/xxhash-wasm": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz",
+      "integrity": "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==",
+      "license": "MIT"
+    },
+    "node_modules/y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "license": "ISC",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yallist": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+      "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/yaml": {
+      "version": "2.8.3",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz",
+      "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==",
+      "license": "ISC",
+      "bin": {
+        "yaml": "bin.mjs"
+      },
+      "engines": {
+        "node": ">= 14.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/eemeli"
+      }
+    },
+    "node_modules/yaml-language-server": {
+      "version": "1.20.0",
+      "resolved": "https://registry.npmjs.org/yaml-language-server/-/yaml-language-server-1.20.0.tgz",
+      "integrity": "sha512-qhjK/bzSRZ6HtTvgeFvjNPJGWdZ0+x5NREV/9XZWFjIGezew2b4r5JPy66IfOhd5OA7KeFwk1JfmEbnTvev0cA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vscode/l10n": "^0.0.18",
+        "ajv": "^8.17.1",
+        "ajv-draft-04": "^1.0.0",
+        "prettier": "^3.5.0",
+        "request-light": "^0.5.7",
+        "vscode-json-languageservice": "4.1.8",
+        "vscode-languageserver": "^9.0.0",
+        "vscode-languageserver-textdocument": "^1.0.1",
+        "vscode-languageserver-types": "^3.16.0",
+        "vscode-uri": "^3.0.2",
+        "yaml": "2.7.1"
+      },
+      "bin": {
+        "yaml-language-server": "bin/yaml-language-server"
+      }
+    },
+    "node_modules/yaml-language-server/node_modules/ajv": {
+      "version": "8.20.0",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
+      "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fast-deep-equal": "^3.1.3",
+        "fast-uri": "^3.0.1",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/yaml-language-server/node_modules/ajv-draft-04": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz",
+      "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "ajv": "^8.5.0"
+      },
+      "peerDependenciesMeta": {
+        "ajv": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/yaml-language-server/node_modules/json-schema-traverse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/yaml-language-server/node_modules/request-light": {
+      "version": "0.5.8",
+      "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.5.8.tgz",
+      "integrity": "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/yaml-language-server/node_modules/yaml": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz",
+      "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "yaml": "bin.mjs"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/yargs": {
+      "version": "18.0.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz",
+      "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "cliui": "^9.0.1",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "string-width": "^7.2.0",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^22.0.0"
+      },
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=23"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "22.0.0",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz",
+      "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==",
+      "license": "ISC",
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=23"
+      }
+    },
+    "node_modules/yargs/node_modules/emoji-regex": {
+      "version": "10.6.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
+      "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/yargs/node_modules/string-width": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+      "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "emoji-regex": "^10.3.0",
+        "get-east-asian-width": "^1.0.0",
+        "strip-ansi": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/yocto-queue": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz",
+      "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12.20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/youch": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/youch/-/youch-4.1.1.tgz",
+      "integrity": "sha512-mxW3qiSnl+GRxXsaUMzv2Mbada1Y8CDltET9UxejDQe6DBYlSekghl5U5K0ReAikcHDi0G1vKZEmmo/NWAGKLA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@poppinss/colors": "^4.1.6",
+        "@poppinss/dumper": "^0.7.0",
+        "@speed-highlight/core": "^1.2.14",
+        "cookie-es": "^3.0.1",
+        "youch-core": "^0.3.3"
+      }
+    },
+    "node_modules/youch-core": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/youch-core/-/youch-core-0.3.3.tgz",
+      "integrity": "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@poppinss/exception": "^1.2.2",
+        "error-stack-parser-es": "^1.0.5"
+      }
+    },
+    "node_modules/youch/node_modules/cookie-es": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-3.1.1.tgz",
+      "integrity": "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/zip-stream": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz",
+      "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "archiver-utils": "^5.0.0",
+        "compress-commons": "^6.0.2",
+        "readable-stream": "^4.0.0"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/zod": {
+      "version": "4.3.6",
+      "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
+      "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/colinhacks"
+      }
+    },
+    "node_modules/zwitch": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",
+      "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    }
+  }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..0b50143
--- /dev/null
+++ b/package.json
@@ -0,0 +1,51 @@
+{
+  "name": "warp-docs",
+  "type": "module",
+  "version": "0.0.1",
+  "license": "MIT",
+  "scripts": {
+    "dev": "astro dev",
+    "build": "astro build",
+    "preview": "astro preview",
+    "astro": "astro",
+    "typecheck": "astro check",
+    "lint": "trunk check",
+    "fmt": "trunk fmt",
+    "og:api": "node scripts/generate-og-api.mjs",
+    "seo:audit": "node scripts/seo-audit.mjs"
+  },
+  "engines": {
+    "node": "^20.19.0 || ^22.12.0 || ^24"
+  },
+  "dependencies": {
+    "@astrojs/react": "^5.0.3",
+    "@astrojs/rss": "^4.0.18",
+    "@astrojs/sitemap": "^3.7.2",
+    "@astrojs/starlight": "^0.38.4",
+    "@astrojs/vercel": "^10.0.4",
+    "@kapaai/react-sdk": "^0.9.2",
+    "@radix-ui/react-popover": "^1.1.15",
+    "@vercel/analytics": "^2.0.0",
+    "@vercel/speed-insights": "^2.0.0",
+    "astro": "^6.1.8",
+    "keymatch": "^1.0.5",
+    "linkedom": "^0.18.12",
+    "react": "^19.2.4",
+    "react-dom": "^19.2.4",
+    "react-icons": "^5.6.0",
+    "react-markdown": "^10.1.0",
+    "sharp": "^0.34.2",
+    "starlight-llms-txt": "^0.8.1",
+    "starlight-sidebar-topics": "^0.7.1",
+    "turndown": "^7.2.2",
+    "turndown-plugin-gfm": "^1.0.2",
+    "yaml": "^2.8.3"
+  },
+  "overrides": {
+    "path-to-regexp": "^6.3.0"
+  },
+  "devDependencies": {
+    "@astrojs/check": "^0.9.8",
+    "typescript": "^5.9.3"
+  }
+}
diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png
new file mode 100644
index 0000000..9fed74d
Binary files /dev/null and b/public/apple-touch-icon.png differ
diff --git a/public/assets/agent-platform/file-based-mcp-toggle.gif b/public/assets/agent-platform/file-based-mcp-toggle.gif
new file mode 100644
index 0000000..0c05571
Binary files /dev/null and b/public/assets/agent-platform/file-based-mcp-toggle.gif differ
diff --git a/public/assets/agent-platform/recreate-universal-input.gif b/public/assets/agent-platform/recreate-universal-input.gif
new file mode 100644
index 0000000..02c2ffe
Binary files /dev/null and b/public/assets/agent-platform/recreate-universal-input.gif differ
diff --git a/public/assets/og/api.png b/public/assets/og/api.png
new file mode 100644
index 0000000..fe3c841
Binary files /dev/null and b/public/assets/og/api.png differ
diff --git a/public/assets/support-and-community/auth-token-demo.mp4 b/public/assets/support-and-community/auth-token-demo.mp4
new file mode 100644
index 0000000..6724e8e
Binary files /dev/null and b/public/assets/support-and-community/auth-token-demo.mp4 differ
diff --git a/public/assets/support-and-community/auth-token-demo.poster.jpg b/public/assets/support-and-community/auth-token-demo.poster.jpg
new file mode 100644
index 0000000..6ec7c5f
Binary files /dev/null and b/public/assets/support-and-community/auth-token-demo.poster.jpg differ
diff --git a/public/assets/support-and-community/check-for-update.gif b/public/assets/support-and-community/check-for-update.gif
new file mode 100644
index 0000000..99ab35e
Binary files /dev/null and b/public/assets/support-and-community/check-for-update.gif differ
diff --git a/public/assets/support-and-community/check-for-update.mp4 b/public/assets/support-and-community/check-for-update.mp4
new file mode 100644
index 0000000..dfa1b00
Binary files /dev/null and b/public/assets/support-and-community/check-for-update.mp4 differ
diff --git a/public/assets/support-and-community/check-for-update.poster.jpg b/public/assets/support-and-community/check-for-update.poster.jpg
new file mode 100644
index 0000000..3e90862
Binary files /dev/null and b/public/assets/support-and-community/check-for-update.poster.jpg differ
diff --git a/public/assets/support-and-community/logout.gif b/public/assets/support-and-community/logout.gif
new file mode 100644
index 0000000..5906d41
Binary files /dev/null and b/public/assets/support-and-community/logout.gif differ
diff --git a/public/assets/support-and-community/logout.mp4 b/public/assets/support-and-community/logout.mp4
new file mode 100644
index 0000000..80bbc43
Binary files /dev/null and b/public/assets/support-and-community/logout.mp4 differ
diff --git a/public/assets/support-and-community/logout.poster.jpg b/public/assets/support-and-community/logout.poster.jpg
new file mode 100644
index 0000000..36e91b8
Binary files /dev/null and b/public/assets/support-and-community/logout.poster.jpg differ
diff --git a/public/assets/support-and-community/open-warp-mac.mp4 b/public/assets/support-and-community/open-warp-mac.mp4
new file mode 100644
index 0000000..b587a94
Binary files /dev/null and b/public/assets/support-and-community/open-warp-mac.mp4 differ
diff --git a/public/assets/support-and-community/open-warp-mac.poster.jpg b/public/assets/support-and-community/open-warp-mac.poster.jpg
new file mode 100644
index 0000000..522fc39
Binary files /dev/null and b/public/assets/support-and-community/open-warp-mac.poster.jpg differ
diff --git a/public/assets/support-and-community/send-feedback-demo.gif b/public/assets/support-and-community/send-feedback-demo.gif
new file mode 100644
index 0000000..9268c76
Binary files /dev/null and b/public/assets/support-and-community/send-feedback-demo.gif differ
diff --git a/public/assets/support-and-community/send-feedback-demo.mp4 b/public/assets/support-and-community/send-feedback-demo.mp4
new file mode 100644
index 0000000..6f1f17a
Binary files /dev/null and b/public/assets/support-and-community/send-feedback-demo.mp4 differ
diff --git a/public/assets/support-and-community/send-feedback-demo.poster.jpg b/public/assets/support-and-community/send-feedback-demo.poster.jpg
new file mode 100644
index 0000000..47b0eb8
Binary files /dev/null and b/public/assets/support-and-community/send-feedback-demo.poster.jpg differ
diff --git a/public/assets/terminal/Dedicated-Window.mp4 b/public/assets/terminal/Dedicated-Window.mp4
new file mode 100644
index 0000000..2a32fb2
Binary files /dev/null and b/public/assets/terminal/Dedicated-Window.mp4 differ
diff --git a/public/assets/terminal/Dedicated-Window.poster.jpg b/public/assets/terminal/Dedicated-Window.poster.jpg
new file mode 100644
index 0000000..f50c1dc
Binary files /dev/null and b/public/assets/terminal/Dedicated-Window.poster.jpg differ
diff --git a/public/assets/terminal/Edit-workflows-autofill.gif b/public/assets/terminal/Edit-workflows-autofill.gif
new file mode 100644
index 0000000..c5fd9fb
Binary files /dev/null and b/public/assets/terminal/Edit-workflows-autofill.gif differ
diff --git a/public/assets/terminal/Edit-workflows-autofill.mp4 b/public/assets/terminal/Edit-workflows-autofill.mp4
new file mode 100644
index 0000000..ac50801
Binary files /dev/null and b/public/assets/terminal/Edit-workflows-autofill.mp4 differ
diff --git a/public/assets/terminal/Edit-workflows-autofill.poster.jpg b/public/assets/terminal/Edit-workflows-autofill.poster.jpg
new file mode 100644
index 0000000..3f4b66a
Binary files /dev/null and b/public/assets/terminal/Edit-workflows-autofill.poster.jpg differ
diff --git a/public/assets/terminal/Show-Hide-All-Windows.mp4 b/public/assets/terminal/Show-Hide-All-Windows.mp4
new file mode 100644
index 0000000..eaa1a5e
Binary files /dev/null and b/public/assets/terminal/Show-Hide-All-Windows.mp4 differ
diff --git a/public/assets/terminal/Show-Hide-All-Windows.poster.jpg b/public/assets/terminal/Show-Hide-All-Windows.poster.jpg
new file mode 100644
index 0000000..1dc9c9e
Binary files /dev/null and b/public/assets/terminal/Show-Hide-All-Windows.poster.jpg differ
diff --git a/public/assets/terminal/block-bookmarks.mp4 b/public/assets/terminal/block-bookmarks.mp4
new file mode 100644
index 0000000..885f120
Binary files /dev/null and b/public/assets/terminal/block-bookmarks.mp4 differ
diff --git a/public/assets/terminal/block-bookmarks.poster.jpg b/public/assets/terminal/block-bookmarks.poster.jpg
new file mode 100644
index 0000000..a8356f7
Binary files /dev/null and b/public/assets/terminal/block-bookmarks.poster.jpg differ
diff --git a/public/assets/terminal/block-divider-demo.gif b/public/assets/terminal/block-divider-demo.gif
new file mode 100644
index 0000000..d8c59f3
Binary files /dev/null and b/public/assets/terminal/block-divider-demo.gif differ
diff --git a/public/assets/terminal/block-divider-demo.mp4 b/public/assets/terminal/block-divider-demo.mp4
new file mode 100644
index 0000000..d084f6d
Binary files /dev/null and b/public/assets/terminal/block-divider-demo.mp4 differ
diff --git a/public/assets/terminal/block-divider-demo.poster.jpg b/public/assets/terminal/block-divider-demo.poster.jpg
new file mode 100644
index 0000000..536e94d
Binary files /dev/null and b/public/assets/terminal/block-divider-demo.poster.jpg differ
diff --git a/public/assets/terminal/block-sharing-embed.mp4 b/public/assets/terminal/block-sharing-embed.mp4
new file mode 100644
index 0000000..cc496f0
Binary files /dev/null and b/public/assets/terminal/block-sharing-embed.mp4 differ
diff --git a/public/assets/terminal/block-sharing-embed.poster.jpg b/public/assets/terminal/block-sharing-embed.poster.jpg
new file mode 100644
index 0000000..41ce96a
Binary files /dev/null and b/public/assets/terminal/block-sharing-embed.poster.jpg differ
diff --git a/public/assets/terminal/block_filtering_toggle.mp4 b/public/assets/terminal/block_filtering_toggle.mp4
new file mode 100644
index 0000000..be7d565
Binary files /dev/null and b/public/assets/terminal/block_filtering_toggle.mp4 differ
diff --git a/public/assets/terminal/block_filtering_toggle.poster.jpg b/public/assets/terminal/block_filtering_toggle.poster.jpg
new file mode 100644
index 0000000..2ef19cc
Binary files /dev/null and b/public/assets/terminal/block_filtering_toggle.poster.jpg differ
diff --git a/public/assets/terminal/block_filtering_with_context_lines.mp4 b/public/assets/terminal/block_filtering_with_context_lines.mp4
new file mode 100644
index 0000000..5b05038
Binary files /dev/null and b/public/assets/terminal/block_filtering_with_context_lines.mp4 differ
diff --git a/public/assets/terminal/block_filtering_with_context_lines.poster.jpg b/public/assets/terminal/block_filtering_with_context_lines.poster.jpg
new file mode 100644
index 0000000..5b4c968
Binary files /dev/null and b/public/assets/terminal/block_filtering_with_context_lines.poster.jpg differ
diff --git a/public/assets/terminal/code-find-menu.mp4 b/public/assets/terminal/code-find-menu.mp4
new file mode 100644
index 0000000..7622708
Binary files /dev/null and b/public/assets/terminal/code-find-menu.mp4 differ
diff --git a/public/assets/terminal/code-find-menu.poster.jpg b/public/assets/terminal/code-find-menu.poster.jpg
new file mode 100644
index 0000000..052f55e
Binary files /dev/null and b/public/assets/terminal/code-find-menu.poster.jpg differ
diff --git a/public/assets/terminal/code-replace-menu.mp4 b/public/assets/terminal/code-replace-menu.mp4
new file mode 100644
index 0000000..5af620c
Binary files /dev/null and b/public/assets/terminal/code-replace-menu.mp4 differ
diff --git a/public/assets/terminal/code-replace-menu.poster.jpg b/public/assets/terminal/code-replace-menu.poster.jpg
new file mode 100644
index 0000000..bb811a8
Binary files /dev/null and b/public/assets/terminal/code-replace-menu.poster.jpg differ
diff --git a/public/assets/terminal/code-review-inline-comment.mp4 b/public/assets/terminal/code-review-inline-comment.mp4
new file mode 100644
index 0000000..c1b1f65
Binary files /dev/null and b/public/assets/terminal/code-review-inline-comment.mp4 differ
diff --git a/public/assets/terminal/code-review-inline-comment.poster.jpg b/public/assets/terminal/code-review-inline-comment.poster.jpg
new file mode 100644
index 0000000..581b5d9
Binary files /dev/null and b/public/assets/terminal/code-review-inline-comment.poster.jpg differ
diff --git a/public/assets/terminal/compact_mode.gif b/public/assets/terminal/compact_mode.gif
new file mode 100644
index 0000000..9aa9ae8
Binary files /dev/null and b/public/assets/terminal/compact_mode.gif differ
diff --git a/public/assets/terminal/compact_mode.mp4 b/public/assets/terminal/compact_mode.mp4
new file mode 100644
index 0000000..ce5f381
Binary files /dev/null and b/public/assets/terminal/compact_mode.mp4 differ
diff --git a/public/assets/terminal/compact_mode.poster.jpg b/public/assets/terminal/compact_mode.poster.jpg
new file mode 100644
index 0000000..ce3fdd7
Binary files /dev/null and b/public/assets/terminal/compact_mode.poster.jpg differ
diff --git a/public/assets/terminal/directly-editing-diffs.gif b/public/assets/terminal/directly-editing-diffs.gif
new file mode 100644
index 0000000..fa033b4
Binary files /dev/null and b/public/assets/terminal/directly-editing-diffs.gif differ
diff --git a/public/assets/terminal/files-links-demo.mp4 b/public/assets/terminal/files-links-demo.mp4
new file mode 100644
index 0000000..b785b5e
Binary files /dev/null and b/public/assets/terminal/files-links-demo.mp4 differ
diff --git a/public/assets/terminal/files-links-demo.poster.jpg b/public/assets/terminal/files-links-demo.poster.jpg
new file mode 100644
index 0000000..e440fe8
Binary files /dev/null and b/public/assets/terminal/files-links-demo.poster.jpg differ
diff --git a/public/assets/terminal/find.mp4 b/public/assets/terminal/find.mp4
new file mode 100644
index 0000000..0291f09
Binary files /dev/null and b/public/assets/terminal/find.mp4 differ
diff --git a/public/assets/terminal/find.poster.jpg b/public/assets/terminal/find.poster.jpg
new file mode 100644
index 0000000..339bfe4
Binary files /dev/null and b/public/assets/terminal/find.poster.jpg differ
diff --git a/public/assets/terminal/jetbrains_external_terminal_config.mp4 b/public/assets/terminal/jetbrains_external_terminal_config.mp4
new file mode 100644
index 0000000..7c5ca7e
Binary files /dev/null and b/public/assets/terminal/jetbrains_external_terminal_config.mp4 differ
diff --git a/public/assets/terminal/jetbrains_external_terminal_config.poster.jpg b/public/assets/terminal/jetbrains_external_terminal_config.poster.jpg
new file mode 100644
index 0000000..60cd53e
Binary files /dev/null and b/public/assets/terminal/jetbrains_external_terminal_config.poster.jpg differ
diff --git a/public/assets/terminal/jetbrains_external_window_keymap_config.mp4 b/public/assets/terminal/jetbrains_external_window_keymap_config.mp4
new file mode 100644
index 0000000..f85d80f
Binary files /dev/null and b/public/assets/terminal/jetbrains_external_window_keymap_config.mp4 differ
diff --git a/public/assets/terminal/jetbrains_external_window_keymap_config.poster.jpg b/public/assets/terminal/jetbrains_external_window_keymap_config.poster.jpg
new file mode 100644
index 0000000..a06549e
Binary files /dev/null and b/public/assets/terminal/jetbrains_external_window_keymap_config.poster.jpg differ
diff --git a/public/assets/terminal/markdown-raw-rendered-toggle.gif b/public/assets/terminal/markdown-raw-rendered-toggle.gif
new file mode 100644
index 0000000..27a4d58
Binary files /dev/null and b/public/assets/terminal/markdown-raw-rendered-toggle.gif differ
diff --git a/public/assets/terminal/notebooks_editor.gif b/public/assets/terminal/notebooks_editor.gif
new file mode 100644
index 0000000..4b9e7ba
Binary files /dev/null and b/public/assets/terminal/notebooks_editor.gif differ
diff --git a/public/assets/terminal/open-markdown-viewer.gif b/public/assets/terminal/open-markdown-viewer.gif
new file mode 100644
index 0000000..838cc78
Binary files /dev/null and b/public/assets/terminal/open-markdown-viewer.gif differ
diff --git a/public/assets/terminal/run-markdown-file-command.mp4 b/public/assets/terminal/run-markdown-file-command.mp4
new file mode 100644
index 0000000..e20a3a0
Binary files /dev/null and b/public/assets/terminal/run-markdown-file-command.mp4 differ
diff --git a/public/assets/terminal/run-markdown-file-command.poster.jpg b/public/assets/terminal/run-markdown-file-command.poster.jpg
new file mode 100644
index 0000000..747425f
Binary files /dev/null and b/public/assets/terminal/run-markdown-file-command.poster.jpg differ
diff --git a/public/assets/terminal/script-demo.mp4 b/public/assets/terminal/script-demo.mp4
new file mode 100644
index 0000000..26a1a8d
Binary files /dev/null and b/public/assets/terminal/script-demo.mp4 differ
diff --git a/public/assets/terminal/script-demo.poster.jpg b/public/assets/terminal/script-demo.poster.jpg
new file mode 100644
index 0000000..7bea842
Binary files /dev/null and b/public/assets/terminal/script-demo.poster.jpg differ
diff --git a/public/assets/terminal/sessions-block_restoration.mp4 b/public/assets/terminal/sessions-block_restoration.mp4
new file mode 100644
index 0000000..4e32265
Binary files /dev/null and b/public/assets/terminal/sessions-block_restoration.mp4 differ
diff --git a/public/assets/terminal/sessions-block_restoration.poster.jpg b/public/assets/terminal/sessions-block_restoration.poster.jpg
new file mode 100644
index 0000000..9d48a43
Binary files /dev/null and b/public/assets/terminal/sessions-block_restoration.poster.jpg differ
diff --git a/public/assets/terminal/split-panes-dragging-demo.mp4 b/public/assets/terminal/split-panes-dragging-demo.mp4
new file mode 100644
index 0000000..7d1d29b
Binary files /dev/null and b/public/assets/terminal/split-panes-dragging-demo.mp4 differ
diff --git a/public/assets/terminal/split-panes-dragging-demo.poster.jpg b/public/assets/terminal/split-panes-dragging-demo.poster.jpg
new file mode 100644
index 0000000..9db2474
Binary files /dev/null and b/public/assets/terminal/split-panes-dragging-demo.poster.jpg differ
diff --git a/public/assets/terminal/sticky-header-toggle-active-demo.gif b/public/assets/terminal/sticky-header-toggle-active-demo.gif
new file mode 100644
index 0000000..242f19a
Binary files /dev/null and b/public/assets/terminal/sticky-header-toggle-active-demo.gif differ
diff --git a/public/assets/terminal/subshell-ssh-demo.mp4 b/public/assets/terminal/subshell-ssh-demo.mp4
new file mode 100644
index 0000000..89d0805
Binary files /dev/null and b/public/assets/terminal/subshell-ssh-demo.mp4 differ
diff --git a/public/assets/terminal/subshell-ssh-demo.poster.jpg b/public/assets/terminal/subshell-ssh-demo.poster.jpg
new file mode 100644
index 0000000..6c2b532
Binary files /dev/null and b/public/assets/terminal/subshell-ssh-demo.poster.jpg differ
diff --git a/public/assets/terminal/subshells-demo.mp4 b/public/assets/terminal/subshells-demo.mp4
new file mode 100644
index 0000000..b868520
Binary files /dev/null and b/public/assets/terminal/subshells-demo.mp4 differ
diff --git a/public/assets/terminal/subshells-demo.poster.jpg b/public/assets/terminal/subshells-demo.poster.jpg
new file mode 100644
index 0000000..3995ec0
Binary files /dev/null and b/public/assets/terminal/subshells-demo.poster.jpg differ
diff --git a/public/assets/terminal/tab-bar-demo.gif b/public/assets/terminal/tab-bar-demo.gif
new file mode 100644
index 0000000..136a85d
Binary files /dev/null and b/public/assets/terminal/tab-bar-demo.gif differ
diff --git a/public/assets/terminal/tab-bar-demo.mp4 b/public/assets/terminal/tab-bar-demo.mp4
new file mode 100644
index 0000000..a3e34db
Binary files /dev/null and b/public/assets/terminal/tab-bar-demo.mp4 differ
diff --git a/public/assets/terminal/tab-bar-demo.poster.jpg b/public/assets/terminal/tab-bar-demo.poster.jpg
new file mode 100644
index 0000000..2d8c2c6
Binary files /dev/null and b/public/assets/terminal/tab-bar-demo.poster.jpg differ
diff --git a/public/assets/terminal/tab-close-button-demo.gif b/public/assets/terminal/tab-close-button-demo.gif
new file mode 100644
index 0000000..c01b668
Binary files /dev/null and b/public/assets/terminal/tab-close-button-demo.gif differ
diff --git a/public/assets/terminal/tab-close-button-demo.mp4 b/public/assets/terminal/tab-close-button-demo.mp4
new file mode 100644
index 0000000..b93d356
Binary files /dev/null and b/public/assets/terminal/tab-close-button-demo.mp4 differ
diff --git a/public/assets/terminal/tab-close-button-demo.poster.jpg b/public/assets/terminal/tab-close-button-demo.poster.jpg
new file mode 100644
index 0000000..7719f8f
Binary files /dev/null and b/public/assets/terminal/tab-close-button-demo.poster.jpg differ
diff --git a/public/assets/terminal/tab-indicator-demo.gif b/public/assets/terminal/tab-indicator-demo.gif
new file mode 100644
index 0000000..e15caac
Binary files /dev/null and b/public/assets/terminal/tab-indicator-demo.gif differ
diff --git a/public/assets/terminal/tab-indicator-demo.mp4 b/public/assets/terminal/tab-indicator-demo.mp4
new file mode 100644
index 0000000..21aa197
Binary files /dev/null and b/public/assets/terminal/tab-indicator-demo.mp4 differ
diff --git a/public/assets/terminal/tab-indicator-demo.poster.jpg b/public/assets/terminal/tab-indicator-demo.poster.jpg
new file mode 100644
index 0000000..c4769c8
Binary files /dev/null and b/public/assets/terminal/tab-indicator-demo.poster.jpg differ
diff --git a/public/assets/terminal/theme-creator.gif b/public/assets/terminal/theme-creator.gif
new file mode 100644
index 0000000..69f7fa9
Binary files /dev/null and b/public/assets/terminal/theme-creator.gif differ
diff --git a/public/assets/terminal/theme-creator.mp4 b/public/assets/terminal/theme-creator.mp4
new file mode 100644
index 0000000..38a33d9
Binary files /dev/null and b/public/assets/terminal/theme-creator.mp4 differ
diff --git a/public/assets/terminal/theme-creator.poster.jpg b/public/assets/terminal/theme-creator.poster.jpg
new file mode 100644
index 0000000..7c6fe78
Binary files /dev/null and b/public/assets/terminal/theme-creator.poster.jpg differ
diff --git a/public/assets/terminal/theme-picker.gif b/public/assets/terminal/theme-picker.gif
new file mode 100644
index 0000000..20d3599
Binary files /dev/null and b/public/assets/terminal/theme-picker.gif differ
diff --git a/public/assets/terminal/theme-picker.mp4 b/public/assets/terminal/theme-picker.mp4
new file mode 100644
index 0000000..da20781
Binary files /dev/null and b/public/assets/terminal/theme-picker.mp4 differ
diff --git a/public/assets/terminal/theme-picker.poster.jpg b/public/assets/terminal/theme-picker.poster.jpg
new file mode 100644
index 0000000..7473ac9
Binary files /dev/null and b/public/assets/terminal/theme-picker.poster.jpg differ
diff --git a/public/assets/terminal/theme-sync-demo.gif b/public/assets/terminal/theme-sync-demo.gif
new file mode 100644
index 0000000..1fa2c83
Binary files /dev/null and b/public/assets/terminal/theme-sync-demo.gif differ
diff --git a/public/assets/terminal/theme-sync-demo.mp4 b/public/assets/terminal/theme-sync-demo.mp4
new file mode 100644
index 0000000..f09652c
Binary files /dev/null and b/public/assets/terminal/theme-sync-demo.mp4 differ
diff --git a/public/assets/terminal/theme-sync-demo.poster.jpg b/public/assets/terminal/theme-sync-demo.poster.jpg
new file mode 100644
index 0000000..5c161f5
Binary files /dev/null and b/public/assets/terminal/theme-sync-demo.poster.jpg differ
diff --git a/public/assets/terminal/vscode_new_session.mp4 b/public/assets/terminal/vscode_new_session.mp4
new file mode 100644
index 0000000..2537afd
Binary files /dev/null and b/public/assets/terminal/vscode_new_session.mp4 differ
diff --git a/public/assets/terminal/vscode_new_session.poster.jpg b/public/assets/terminal/vscode_new_session.poster.jpg
new file mode 100644
index 0000000..34d9d16
Binary files /dev/null and b/public/assets/terminal/vscode_new_session.poster.jpg differ
diff --git a/public/assets/terminal/warp-custom-prompt-demo.mp4 b/public/assets/terminal/warp-custom-prompt-demo.mp4
new file mode 100644
index 0000000..269e5d3
Binary files /dev/null and b/public/assets/terminal/warp-custom-prompt-demo.mp4 differ
diff --git a/public/assets/terminal/warp-custom-prompt-demo.poster.jpg b/public/assets/terminal/warp-custom-prompt-demo.poster.jpg
new file mode 100644
index 0000000..528a25c
Binary files /dev/null and b/public/assets/terminal/warp-custom-prompt-demo.poster.jpg differ
diff --git a/public/assets/terminal/window_size_demo.mp4 b/public/assets/terminal/window_size_demo.mp4
new file mode 100644
index 0000000..a57150f
Binary files /dev/null and b/public/assets/terminal/window_size_demo.mp4 differ
diff --git a/public/assets/terminal/window_size_demo.poster.jpg b/public/assets/terminal/window_size_demo.poster.jpg
new file mode 100644
index 0000000..7a86bab
Binary files /dev/null and b/public/assets/terminal/window_size_demo.poster.jpg differ
diff --git a/public/assets/terminal/working-directory-demo.mp4 b/public/assets/terminal/working-directory-demo.mp4
new file mode 100644
index 0000000..6f213bc
Binary files /dev/null and b/public/assets/terminal/working-directory-demo.mp4 differ
diff --git a/public/assets/terminal/working-directory-demo.poster.jpg b/public/assets/terminal/working-directory-demo.poster.jpg
new file mode 100644
index 0000000..5972cd0
Binary files /dev/null and b/public/assets/terminal/working-directory-demo.poster.jpg differ
diff --git a/public/assets/terminal/yaml_workflows_demo.gif b/public/assets/terminal/yaml_workflows_demo.gif
new file mode 100644
index 0000000..e4870de
Binary files /dev/null and b/public/assets/terminal/yaml_workflows_demo.gif differ
diff --git a/public/assets/terminal/yaml_workflows_demo.mp4 b/public/assets/terminal/yaml_workflows_demo.mp4
new file mode 100644
index 0000000..a4ed9f8
Binary files /dev/null and b/public/assets/terminal/yaml_workflows_demo.mp4 differ
diff --git a/public/assets/terminal/yaml_workflows_demo.poster.jpg b/public/assets/terminal/yaml_workflows_demo.poster.jpg
new file mode 100644
index 0000000..b4faf37
Binary files /dev/null and b/public/assets/terminal/yaml_workflows_demo.poster.jpg differ
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000..b9ebc2a
Binary files /dev/null and b/public/favicon.ico differ
diff --git a/public/favicon.svg b/public/favicon.svg
new file mode 100644
index 0000000..e951835
--- /dev/null
+++ b/public/favicon.svg
@@ -0,0 +1 @@
+
diff --git a/public/og-image.png b/public/og-image.png
new file mode 100644
index 0000000..826beef
Binary files /dev/null and b/public/og-image.png differ
diff --git a/public/robots.txt b/public/robots.txt
new file mode 100644
index 0000000..988aefb
--- /dev/null
+++ b/public/robots.txt
@@ -0,0 +1,7 @@
+User-agent: *
+Allow: /
+Disallow: /*?*q=*
+Disallow: /*?*ask=*
+Content-Signal: ai-train=yes, search=yes, ai-input=yes
+
+Sitemap: https://docs.warp.dev/sitemap-index.xml
diff --git a/scripts/check_redirects.py b/scripts/check_redirects.py
new file mode 100644
index 0000000..7a418ea
--- /dev/null
+++ b/scripts/check_redirects.py
@@ -0,0 +1,253 @@
+#!/usr/bin/env python3
+"""Validate vercel.json redirects.
+
+Static mode (default): for each redirect, check that the `destination`
+resolves to a page that actually exists in `src/content/docs/`. External
+URLs and special endpoints (`/api`, `/api#...`) are skipped.
+
+Live mode (--live URL): actually hit each `source` against a deployed
+preview/production URL and verify it returns the expected status code
+with a `location` header pointing at the configured destination.
+
+Usage:
+
+    # Static check (fast, no network)
+    python3 scripts/check_redirects.py
+
+    # Live check against a Vercel preview deployment
+    python3 scripts/check_redirects.py --live https://docs-git-.vercel.app
+
+    # Live check, sample only 50 redirects (useful for spot-checks)
+    python3 scripts/check_redirects.py --live  --sample 50
+
+    # Static check + live check together
+    python3 scripts/check_redirects.py --live 
+
+Exit code is 0 if all checks pass, 1 if any redirect is broken.
+"""
+from __future__ import annotations
+
+import argparse
+import json
+import random
+import re
+import sys
+from concurrent.futures import ThreadPoolExecutor, as_completed
+from pathlib import Path
+from urllib.parse import urlparse
+
+REPO = Path(__file__).resolve().parent.parent
+DOCS = REPO / "src" / "content" / "docs"
+VERCEL_JSON = REPO / "vercel.json"
+
+# Destinations starting with these prefixes are not Astro Starlight pages and
+# should not be checked for file existence.
+SKIP_DEST_PREFIXES = (
+    "http://",
+    "https://",
+    "/api",  # OpenAPI reference, served by starlight-openapi
+    "/_astro/",
+    "/assets/",
+)
+
+# Destination paths ending in these extensions are generated assets
+# (RSS feeds, sitemaps, etc.), not Starlight content pages.
+SKIP_DEST_EXTENSIONS = (
+    ".xml",
+    ".json",
+    ".txt",
+    ".png",
+    ".jpg",
+    ".gif",
+    ".svg",
+    ".ico",
+)
+
+
+def load_redirects() -> list[dict]:
+    with VERCEL_JSON.open() as f:
+        data = json.load(f)
+    return data.get("redirects", [])
+
+
+def url_to_content_path(url_path: str) -> Path | None:
+    """Map a URL like '/foo/bar/' to a content file path.
+
+    Returns the file Path if it exists, or None if no file matches.
+    Tries both `foo/bar.mdx` and `foo/bar/index.mdx` conventions.
+    """
+    # Strip leading slash, trailing slash, and any anchor/query.
+    path = url_path.split("#", 1)[0].split("?", 1)[0]
+    path = path.strip("/")
+    if not path:
+        return DOCS / "index.mdx" if (DOCS / "index.mdx").exists() else None
+
+    candidates = [
+        DOCS / f"{path}.mdx",
+        DOCS / f"{path}.md",
+        DOCS / path / "index.mdx",
+        DOCS / path / "index.md",
+    ]
+    for c in candidates:
+        if c.exists():
+            return c
+    return None
+
+
+def static_check(redirects: list[dict]) -> tuple[int, int, list[str]]:
+    """Verify each destination resolves to a real page.
+
+    Returns (checked, broken, errors).
+    """
+    checked = 0
+    broken = 0
+    errors: list[str] = []
+
+    for r in redirects:
+        source = r.get("source", "")
+        dest = r.get("destination", "")
+        if not source or not dest:
+            errors.append(f"Missing source/destination: {r!r}")
+            broken += 1
+            continue
+
+        # Skip wildcard sources/destinations — we can't fully verify these
+        # statically since the captured group is dynamic.
+        if "(" in source or "$" in dest:
+            continue
+
+        # Skip external URLs and special endpoints.
+        if dest.startswith(SKIP_DEST_PREFIXES):
+            continue
+
+        # Skip generated assets (RSS feeds, sitemaps, etc.).
+        dest_path = dest.split("#", 1)[0].split("?", 1)[0]
+        if dest_path.endswith(SKIP_DEST_EXTENSIONS):
+            continue
+
+        checked += 1
+        path = url_to_content_path(dest)
+        if path is None:
+            errors.append(f"Destination not found: {source!r} -> {dest!r}")
+            broken += 1
+
+    return checked, broken, errors
+
+
+def live_check_one(base_url: str, redirect: dict, timeout: float = 10.0) -> tuple[bool, str]:
+    """Hit one source URL and verify the redirect.
+
+    Returns (ok, message). ok=True if the redirect matches, False otherwise.
+    """
+    import urllib.request
+    import urllib.error
+
+    source = redirect["source"]
+    expected_dest = redirect["destination"]
+    expected_status = redirect.get("statusCode", 308)
+
+    # Skip wildcard redirects in live mode — we'd need to substitute $1 etc.
+    if "(" in source or "$" in expected_dest:
+        return True, f"SKIP (wildcard): {source}"
+
+    url = base_url.rstrip("/") + source
+    req = urllib.request.Request(url, method="HEAD")
+    try:
+        # Don't follow redirects — we want to inspect the response headers.
+        opener = urllib.request.build_opener(NoRedirect())
+        with opener.open(req, timeout=timeout) as resp:
+            status = resp.status
+            location = resp.headers.get("location", "")
+    except urllib.error.HTTPError as e:
+        status = e.code
+        location = e.headers.get("location", "") if e.headers else ""
+    except Exception as e:  # noqa: BLE001
+        return False, f"ERROR {source}: {e}"
+
+    if status != expected_status:
+        return False, f"FAIL {source}: status {status} != {expected_status}"
+    # Location may be relative (just the path) or absolute. Compare paths.
+    actual_path = urlparse(location).path or location
+    if actual_path != expected_dest:
+        return False, (
+            f"FAIL {source}: location {actual_path!r} != {expected_dest!r}"
+        )
+    return True, f"OK {source} -> {expected_dest}"
+
+
+class NoRedirect(__import__("urllib.request").request.HTTPRedirectHandler):
+    """An HTTP handler that does NOT follow redirects."""
+
+    def http_error_301(self, req, fp, code, msg, headers):  # noqa: D102
+        raise __import__("urllib.error").error.HTTPError(req.full_url, code, msg, headers, fp)
+
+    http_error_302 = http_error_301
+    http_error_303 = http_error_301
+    http_error_307 = http_error_301
+    http_error_308 = http_error_301
+
+
+def live_check(base_url: str, redirects: list[dict], sample: int = 0, workers: int = 16) -> tuple[int, int, list[str]]:
+    """Hit redirects against a live URL. Returns (checked, broken, errors)."""
+    if sample and sample < len(redirects):
+        redirects = random.sample(redirects, sample)
+
+    checked = 0
+    broken = 0
+    errors: list[str] = []
+
+    with ThreadPoolExecutor(max_workers=workers) as pool:
+        futures = {pool.submit(live_check_one, base_url, r): r for r in redirects}
+        for i, fut in enumerate(as_completed(futures), 1):
+            ok, msg = fut.result()
+            if msg.startswith("SKIP"):
+                continue
+            checked += 1
+            if not ok:
+                broken += 1
+                errors.append(msg)
+            if i % 50 == 0:
+                print(f"  ... {i}/{len(futures)} ({broken} broken so far)", file=sys.stderr)
+
+    return checked, broken, errors
+
+
+def main() -> int:
+    parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
+    parser.add_argument("--live", metavar="URL", help="Base URL of a deployed site (e.g. Vercel preview) to hit for live checks")
+    parser.add_argument("--sample", type=int, default=0, help="Live mode only: check a random sample of N redirects instead of all")
+    parser.add_argument("--workers", type=int, default=16, help="Live mode only: concurrent HTTP workers (default 16)")
+    parser.add_argument("--skip-static", action="store_true", help="Skip the static check (only meaningful with --live)")
+    args = parser.parse_args()
+
+    redirects = load_redirects()
+    print(f"Loaded {len(redirects)} redirects from {VERCEL_JSON.relative_to(REPO)}")
+
+    total_broken = 0
+
+    # Static check
+    if not args.skip_static:
+        print("\n=== Static check (destination existence) ===")
+        checked, broken, errors = static_check(redirects)
+        print(f"Checked: {checked}, broken: {broken}")
+        for err in errors:
+            print(f"  {err}")
+        total_broken += broken
+
+    # Live check
+    if args.live:
+        print(f"\n=== Live check against {args.live} ===")
+        if args.sample:
+            print(f"Sampling {args.sample} of {len(redirects)} redirects")
+        checked, broken, errors = live_check(args.live, redirects, sample=args.sample, workers=args.workers)
+        print(f"Checked: {checked}, broken: {broken}")
+        for err in errors:
+            print(f"  {err}")
+        total_broken += broken
+
+    print(f"\n{'PASS' if total_broken == 0 else 'FAIL'}: {total_broken} broken")
+    return 0 if total_broken == 0 else 1
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/scripts/convert-gitbook.py b/scripts/convert-gitbook.py
new file mode 100755
index 0000000..a4b347e
--- /dev/null
+++ b/scripts/convert-gitbook.py
@@ -0,0 +1,786 @@
+#!/usr/bin/env python3
+"""Convert GitBook markdown files to Astro Starlight MDX format.
+
+Usage:
+    python scripts/convert-gitbook.py    [--skip-existing]
+
+Example:
+    python scripts/convert-gitbook.py \
+        /path/to/gitbook/docs/agent-platform \
+        /path/to/docs/src/content/docs/agent-platform \
+        agent-platform \
+        --skip-existing
+"""
+
+import re
+import sys
+import shutil
+from pathlib import Path
+
+# ---------------------------------------------------------------------------
+# Config
+# ---------------------------------------------------------------------------
+
+HINT_MAP = {
+    "info": "note",
+    "warning": "caution",
+    "danger": "danger",
+    "success": "tip",
+}
+
+KEEP_FRONTMATTER_KEYS = {"title", "description"}
+
+# ---------------------------------------------------------------------------
+# Frontmatter
+# ---------------------------------------------------------------------------
+
+
+def parse_frontmatter(content: str) -> tuple[dict, str]:
+    """Return (frontmatter_dict, body) from raw file content."""
+    if not content.startswith("---"):
+        return {}, content
+    end = content.find("\n---", 3)
+    if end == -1:
+        return {}, content
+    raw_fm = content[3:end].strip()
+    body = content[end + 4:]  # skip past closing ---\n
+
+    fm: dict = {}
+    current_key = None
+    current_val_lines: list[str] = []
+
+    for line in raw_fm.split("\n"):
+        # Continuation of multi-line value (indented or >- style)
+        if current_key and (line.startswith("  ") or line.strip() == ""):
+            current_val_lines.append(line)
+            continue
+
+        # Save previous key
+        if current_key:
+            fm[current_key] = "\n".join(current_val_lines).strip()
+            current_key = None
+            current_val_lines = []
+
+        m = re.match(r"^(\w[\w-]*):\s*(.*)", line)
+        if m:
+            current_key = m.group(1)
+            rest = m.group(2).strip()
+            if rest == ">-" or rest == ">":
+                current_val_lines = []
+            else:
+                current_val_lines = [rest]
+
+    if current_key:
+        fm[current_key] = "\n".join(current_val_lines).strip()
+
+    return fm, body
+
+
+def build_frontmatter(fm: dict, body: str) -> str:
+    """Build clean YAML frontmatter string."""
+    # If there's no title in frontmatter, extract from first H1
+    if "title" not in fm:
+        m = re.search(r"^#\s+(.+)$", body, re.MULTILINE)
+        if m:
+            fm["title"] = m.group(1).strip()
+
+    lines = ["---"]
+    if "title" in fm:
+        title = fm["title"].strip('"').strip("'")
+        if any(c in title for c in ":#{}[]|>&*!%@`"):
+            lines.append(f'title: "{title}"')
+        else:
+            lines.append(f"title: {title}")
+    if "description" in fm:
+        desc = fm["description"].strip()
+        lines.append("description: >-")
+        words = desc.split()
+        current_line = "  "
+        for word in words:
+            if len(current_line) + len(word) + 1 > 78:
+                lines.append(current_line)
+                current_line = "  " + word
+            else:
+                current_line += (" " if len(current_line) > 2 else "") + word
+        if current_line.strip():
+            lines.append(current_line)
+    lines.append("---")
+    return "\n".join(lines)
+
+
+def strip_first_h1(body: str) -> str:
+    """Remove the first H1 heading (title is now in frontmatter)."""
+    return re.sub(r"^#\s+.+\n?", "", body, count=1, flags=re.MULTILINE)
+
+
+# ---------------------------------------------------------------------------
+# Hints -> Asides
+# ---------------------------------------------------------------------------
+
+
+def convert_hints(content: str) -> str:
+    """Convert {% hint style='X' %}...{% endhint %} to :::type asides.
+
+    Tolerates extra attributes after `style="..."` (e.g. `icon="comment"`).
+    """
+
+    def _replace_hint(m):
+        style = m.group(1)
+        aside_type = HINT_MAP.get(style, "note")
+        inner = m.group(2).strip()
+        return f":::{aside_type}\n{inner}\n:::"
+
+    pattern = r'\{%\s*hint\s+style="(\w+)"[^%]*%\}(.*?)\{%\s*endhint\s*%\}'
+    return re.sub(pattern, _replace_hint, content, flags=re.DOTALL)
+
+
+# ---------------------------------------------------------------------------
+# Tabs -> MDX Tabs / TabItem
+# ---------------------------------------------------------------------------
+
+
+def convert_tabs(content: str) -> str:
+    """Convert {% tabs %}...{% endtabs %} to / components."""
+
+    def _replace_tabs_block(m):
+        inner = m.group(1)
+        result_parts = [""]
+
+        tab_pattern = r'\{%\s*tab\s+title="([^"]+)"\s*%\}(.*?)\{%\s*endtab\s*%\}'
+        tabs = re.findall(tab_pattern, inner, flags=re.DOTALL)
+
+        for title, tab_content in tabs:
+            content_stripped = tab_content.strip()
+            result_parts.append(f'  ')
+            for line in content_stripped.split("\n"):
+                result_parts.append(f"    {line}" if line.strip() else "")
+            result_parts.append("  ")
+
+        result_parts.append("")
+        return "\n".join(result_parts)
+
+    pattern = r"\{%\s*tabs\s*%\}(.*?)\{%\s*endtabs\s*%\}"
+    return re.sub(pattern, _replace_tabs_block, content, flags=re.DOTALL)
+
+
+# ---------------------------------------------------------------------------
+# Embeds -> VideoEmbed
+# ---------------------------------------------------------------------------
+
+
+def convert_embeds(content: str) -> str:
+    """Convert {% embed url='X' %} to ."""
+
+    # Pattern 1: embed with endembed (may have caption text between)
+    def _replace_embed_with_end(m):
+        url = m.group(1)
+        caption = m.group(2).strip()
+        if caption:
+            return f''
+        return f''
+
+    # Use negative lookahead to prevent spanning across other embed blocks
+    content = re.sub(
+        r'\{%\s*embed\s+url="([^"]+)"\s*%\}\s*\n?((?:(?!\{%\s*embed).)*?)\{%\s*endembed\s*%\}',
+        _replace_embed_with_end,
+        content,
+        flags=re.DOTALL,
+    )
+
+    # Pattern 2: standalone embed (no endembed)
+    content = re.sub(
+        r'\{%\s*embed\s+url="([^"]+)"\s*%\}',
+        r'',
+        content,
+    )
+
+    return content
+
+
+# ---------------------------------------------------------------------------
+# Figures -> Markdown images
+# ---------------------------------------------------------------------------
+
+
+def convert_figures(content: str, rel_asset_prefix: str) -> str:
+    """Convert 
tags to markdown images.""" + + def _replace_figure(m): + full = m.group(0) + src_m = re.search(r'src="([^"]*)"', full) + alt_m = re.search(r'alt="([^"]*)"', full) + caption_m = re.search( + r"
(?:

)?(.*?)(?:

)?
", full, re.DOTALL + ) + + if not src_m: + return full + + src = src_m.group(1) + alt = alt_m.group(1) if alt_m else "" + caption = caption_m.group(1).strip() if caption_m else "" + display_alt = alt or caption + + # Rewrite .gitbook/assets/ paths + asset_filename = src.split("/")[-1] + if ".gitbook/assets/" in src: + # Sanitize filename for web compatibility + safe_filename = sanitize_asset_filename(asset_filename) + new_src = f"{rel_asset_prefix}{safe_filename}" + else: + new_src = src + + return f"![{display_alt}]({new_src})" + + pattern = r"
.*?
" + return re.sub(pattern, _replace_figure, content, flags=re.DOTALL) + + +def convert_inline_images(content: str, rel_asset_prefix: str) -> str: + """Rewrite plain markdown images that point at `.gitbook/assets/` to the + Starlight asset directory. + + Some pages use `![alt](../../.gitbook/assets/foo.png)` directly instead of + wrapping in `
`. The figure converter doesn't touch those, so we + handle them here. + """ + + def _rewrite(m): + alt = m.group(1) + src = m.group(2) + if ".gitbook/assets/" not in src: + return m.group(0) + # Strip any URL fragment / query and pull the filename off the end. + bare = src.split("#", 1)[0].split("?", 1)[0] + asset_filename = bare.split("/")[-1] + safe_filename = sanitize_asset_filename(asset_filename) + return f"![{alt}]({rel_asset_prefix}{safe_filename})" + + return re.sub(r"!\[([^\]]*)\]\(([^)]+)\)", _rewrite, content) + + +# --------------------------------------------------------------------------- +# Code blocks +# --------------------------------------------------------------------------- + + +def convert_code_blocks(content: str) -> str: + """Convert {% code %} wrappers (strip them; fenced blocks are fine as-is).""" + content = re.sub(r"\{%\s*code[^%]*%\}\s*\n", "", content) + content = re.sub(r"\{%\s*endcode\s*%\}\s*\n?", "", content) + return content + + +# --------------------------------------------------------------------------- +# Internal links +# --------------------------------------------------------------------------- + + +def convert_links(content: str, file_rel_dir: str, space: str) -> str: + """Rewrite relative .md links to absolute /space/... paths.""" + + def _rewrite_link(m): + text = m.group(1) + href = m.group(2) + fragment = "" + + # Skip external, absolute, anchor-only, and mailto links + if href.startswith(("http://", "https://", "/", "#", "mailto:")): + return m.group(0) + + # Separate fragment + if "#" in href: + href, fragment = href.split("#", 1) + fragment = "#" + fragment + + if not href: + return m.group(0) + + # Normalise the path relative to the current file's directory + parts = ((file_rel_dir + "/" + href) if file_rel_dir else href).split("/") + normalised = [] + for p in parts: + if p == "..": + if normalised: + normalised.pop() + elif p and p != ".": + normalised.append(p) + rel = "/".join(normalised) + + # README.md -> directory path + rel = re.sub(r"/README\.md$", "/", rel) + rel = re.sub(r"^README\.md$", "", rel) + # .md -> / + rel = re.sub(r"\.md$", "/", rel) + + # Build absolute path + abs_path = f"/{space}/{rel}" if rel else f"/{space}/" + + # Clean up double slashes + while "//" in abs_path: + abs_path = abs_path.replace("//", "/") + + # Ensure trailing slash before fragment + if not abs_path.endswith("/"): + abs_path += "/" + + return f"[{text}]({abs_path}{fragment})" + + # Negative lookbehind to skip image links ![alt](url) + return re.sub(r"(? str: + """Insert required MDX imports after frontmatter.""" + imports = [] + if "" in content or "" in content: + imports.append( + "import { Steps } from '@astrojs/starlight/components';" + ) + + if not imports: + return content + + import_block = "\n".join(imports) + + # Insert after frontmatter closing --- + if content.startswith("---"): + end = content.find("\n---", 3) + if end != -1: + insert_pos = end + 4 + return ( + content[:insert_pos] + "\n" + import_block + "\n" + content[insert_pos:] + ) + + return import_block + "\n\n" + content + + +# --------------------------------------------------------------------------- +# HTML comments -> MDX-safe comments +# --------------------------------------------------------------------------- + + +def convert_html_comments(content: str) -> str: + """Wrap HTML comments in {/* */} for MDX compatibility.""" + + def _replace_comment(m): + body = m.group(1) + return "{/* " + body.strip() + " */}" + + return re.sub(r"", _replace_comment, content, flags=re.DOTALL) + + +# --------------------------------------------------------------------------- +# Steppers -> Steps component +# --------------------------------------------------------------------------- + + +def convert_steppers(content: str) -> str: + """Convert {% stepper %}...{% endstepper %} to with ordered list.""" + + def _replace_stepper(m): + inner = m.group(1) + + # Split into individual steps + step_pattern = r'\{%\s*step\s*%\}(.*?)\{%\s*endstep\s*%\}' + steps = re.findall(step_pattern, inner, flags=re.DOTALL) + + if not steps: + return inner.strip() + + result_parts = [""] + for i, step_content in enumerate(steps, 1): + lines = step_content.strip().split("\n") + # Indent all content under the list item + indented = [] + for j, line in enumerate(lines): + if j == 0: + # First line starts the ordered list item + indented.append(f"{i}. {line}") + else: + indented.append(f" {line}" if line.strip() else "") + result_parts.append("\n".join(indented)) + + result_parts.append("") + return "\n\n".join(result_parts) + + pattern = r'\{%\s*stepper\s*%\}(.*?)\{%\s*endstepper\s*%\}' + return re.sub(pattern, _replace_stepper, content, flags=re.DOTALL) + + +# --------------------------------------------------------------------------- +# GitBook card tables -> ImageGrid +# --------------------------------------------------------------------------- + + +def convert_gitbook_card_tables( + content: str, rel_asset_prefix: str, src_label: str = "" +) -> str: + """Convert blocks to /. + + GitBook's card tables come in two flavours: + 1. Image showcase grids (icons, themes) – each row has an + label. + 2. Link-card grids (guide landing pages) – each row has a content-ref link. + + This function converts image-based card tables to the custom ImageGrid + component. Link-card tables (no tags) are stripped; they should be + rebuilt manually with Starlight's / components. + """ + + def _replace_card_table(m): + table_html = m.group(0) + + # Extract rows: each in is one card + row_pattern = r'(.*?)' + rows = re.findall(row_pattern, table_html, flags=re.DOTALL) + if not rows: + return '' # empty table, strip it + + # Check if this is an image grid (contains tags) + if '/") + return '{/* TODO: convert link-card table to / */}' + + items = [] + for row in rows: + # Extract image src + src_m = re.search(r'src="([^"]*)"', row) + if not src_m: + continue + src = src_m.group(1) + asset_filename = src.split('/')[-1] + if '.gitbook/assets/' in src: + safe_filename = sanitize_asset_filename(asset_filename) + else: + safe_filename = asset_filename + + # Extract label: text content of a ' + tds = re.findall(td_pattern, row, flags=re.DOTALL) + for td_content in tds: + stripped = re.sub(r'<[^>]+>', '', td_content).strip() + if stripped and ''] + for var_name, _filename, label in items: + grid_lines.append(f' ') + grid_lines.append('') + + import_comment_lines = [ + '{/* ImageGrid imports needed:', + "import ImageGrid from '@components/ImageGrid.astro';", + "import ImageGridItem from '@components/ImageGridItem.astro';", + ] + for var_name, filename, _label in items: + import_comment_lines.append( + f"import {var_name} from '{rel_asset_prefix}{filename}';" + ) + import_comment_lines.append('*/}') + + return '\n'.join(import_comment_lines) + '\n\n' + '\n'.join(grid_lines) + + return re.sub( + r'.*?
that doesn't contain + label = '' + td_pattern = r']*>(.*?)
', + _replace_card_table, + content, + flags=re.DOTALL, + ) + + +def strip_gitbook_content_refs(content: str) -> str: + """Strip {% content-ref %}...{% endcontent-ref %} wrappers, keeping inner. + + GitBook renders these as link cards. In Starlight we just preserve the + inner markdown link (the converter's link rewrite step already handled + the URL). + """ + return re.sub( + r'\{%\s*content-ref[^%]*%\}\s*\n?(.*?)\{%\s*endcontent-ref\s*%\}', + lambda m: m.group(1).strip(), + content, + flags=re.DOTALL, + ) + + +# --------------------------------------------------------------------------- +# Misc cleanup +# --------------------------------------------------------------------------- + + +def strip_custom_anchors(content: str) -> str: + """Remove GitBook custom anchor HTML like .""" + return re.sub(r'\s*\s*', "", content) + + +def convert_horizontal_rules(content: str) -> str: + """Normalise *** horizontal rules to ---.""" + return re.sub(r"^\*{3,}$", "---", content, flags=re.MULTILINE) + + +def sanitize_html_tables(content: str) -> str: + """Escape markdown-special characters inside HTML table content for MDX.""" + + def _sanitize_table(m): + table = m.group(0) + # Escape * and _ when they appear as text content inside tags + # * -> {'*'} + table = re.sub( + r"([^<]*\*[^<]*)", + lambda cm: "" + cm.group(1).replace("*", "{'*'}") + "", + table, + ) + # Escape bare * between tags that could be interpreted as emphasis + # Only in table cells: > * < pattern + table = re.sub(r">\s*\*\s*<", "> {'*'} <", table) + return table + + return re.sub(r".*?
", _sanitize_table, content, flags=re.DOTALL) + + +def fix_html_void_elements(content: str) -> str: + """Convert void HTML elements to self-closing for MDX compatibility.""" + #
->
, -> ,
->
+ for tag in ["br", "hr", "img"]: + content = re.sub( + rf"<({tag})(\s[^>]*)?>(?!\s*/)", + lambda m: f"<{m.group(1)}{m.group(2) or ''} />", + content, + ) + return content + + +def convert_autolinks(content: str) -> str: + """Convert markdown autolinks `` to inline link form. + + MDX treats `<...>` as JSX, so the bare-URL autolink syntax that's valid + GitHub-Flavored Markdown breaks the MDX parser. Rewrite each occurrence as + `[https://example.com](https://example.com)` so the rendered link is + identical. + """ + return re.sub( + r"<((?:https?|mailto):[^\s<>]+)>", + lambda m: f"[{m.group(1)}]({m.group(1)})", + content, + ) + + +# --------------------------------------------------------------------------- +# Asset prefix calculation +# --------------------------------------------------------------------------- + + +def compute_rel_asset_prefix(dst_rel_path: Path, space: str) -> str: + """Compute relative path from a doc file to src/assets//. + + dst_rel_path is relative to the space docs dir (e.g. 'capabilities/skills.mdx'). + The docs dir is at src/content/docs// and assets at src/assets//. + """ + depth = len(dst_rel_path.parent.parts) + # From content/docs// up to src/: 3 + depth + ups = 3 + depth + return "../" * ups + f"assets/{space}/" + + +# --------------------------------------------------------------------------- +# Main conversion +# --------------------------------------------------------------------------- + + +def convert_file( + src_path: Path, dst_path: Path, space: str, gitbook_root: Path +) -> str: + """Convert a single GitBook markdown file to Starlight MDX.""" + content = src_path.read_text(encoding="utf-8") + + # Determine relative directory within the space + try: + file_rel = src_path.relative_to(gitbook_root) + except ValueError: + file_rel = Path(src_path.name) + file_rel_dir = str(file_rel.parent) if str(file_rel.parent) != "." else "" + + # Compute asset prefix from destination path + dst_str = str(dst_path) + space_marker = f"docs/{space}/" + if space_marker in dst_str: + after_space = dst_str.split(space_marker, 1)[1] + dst_rel_in_space = Path(after_space) + else: + dst_rel_in_space = Path(dst_path.name) + + rel_asset_prefix = compute_rel_asset_prefix(dst_rel_in_space, space) + + # 1. Parse and rebuild frontmatter + fm, body = parse_frontmatter(content) + for key in list(fm.keys()): + if key not in KEEP_FRONTMATTER_KEYS: + del fm[key] + new_fm = build_frontmatter(fm, body) + body = strip_first_h1(body) + + # 2. Apply transforms (order matters) + body = convert_hints(body) + body = convert_embeds(body) + body = convert_tabs(body) + body = convert_code_blocks(body) + body = convert_steppers(body) + body = convert_gitbook_card_tables(body, rel_asset_prefix, src_label=str(file_rel)) + body = strip_gitbook_content_refs(body) + body = convert_figures(body, rel_asset_prefix) + body = convert_inline_images(body, rel_asset_prefix) + body = convert_links(body, file_rel_dir, space) + body = convert_html_comments(body) + body = strip_custom_anchors(body) + body = convert_horizontal_rules(body) + body = sanitize_html_tables(body) + body = fix_html_void_elements(body) + body = convert_autolinks(body) + + # 3. Reassemble + result = new_fm + "\n" + body + + # 4. Inject MDX imports + result = inject_imports(result) + + # 5. Clean up excessive blank lines + result = re.sub(r"\n{3,}", "\n\n", result) + + if not result.endswith("\n"): + result += "\n" + + return result + + +def sanitize_asset_filename(name: str) -> str: + """Replace spaces and parens in asset filenames for web compatibility.""" + return name.replace(" ", "-").replace("(", "").replace(")", "") + + +def collect_referenced_assets(gitbook_root: Path) -> dict[str, str]: + """Find all asset filenames referenced in GitBook source files. + + Returns a dict mapping original_filename -> sanitized_filename. + """ + assets: dict[str, str] = {} + for md_file in gitbook_root.rglob("*.md"): + if md_file.name == "SUMMARY.md": + continue + content = md_file.read_text(encoding="utf-8") + # Match .gitbook/assets/FILENAME where filename may contain spaces + for m in re.finditer(r'\.gitbook/assets/([^"]+)', content): + original = m.group(1).strip() + if original: + assets[original] = sanitize_asset_filename(original) + return assets + + +def main(): + if len(sys.argv) < 4: + print(__doc__) + sys.exit(1) + + gitbook_root = Path(sys.argv[1]).resolve() + starlight_docs = Path(sys.argv[2]).resolve() + space = sys.argv[3] + skip_existing = "--skip-existing" in sys.argv + + if not gitbook_root.is_dir(): + print(f"Error: {gitbook_root} is not a directory") + sys.exit(1) + + # Collect all .md files (skip SUMMARY.md) + md_files = sorted( + p for p in gitbook_root.rglob("*.md") if p.name != "SUMMARY.md" + ) + + # Determine which files to skip (already migrated) + skip_set: set[str] = set() + if skip_existing: + for existing in starlight_docs.rglob("*.mdx"): + try: + rel = existing.relative_to(starlight_docs) + except ValueError: + continue + src_name = ( + "README.md" if rel.name == "index.mdx" else rel.stem + ".md" + ) + src_rel = rel.parent / src_name + skip_set.add(str(src_rel)) + + converted = 0 + skipped = 0 + + for src_path in md_files: + rel = src_path.relative_to(gitbook_root) + if str(rel) in skip_set: + skipped += 1 + print(f" ⊘ {rel} (already exists)") + continue + + # Compute destination path + dst_rel = rel + if dst_rel.name == "README.md": + dst_rel = dst_rel.parent / "index.mdx" + else: + dst_rel = dst_rel.with_suffix(".mdx") + + dst_path = starlight_docs / dst_rel + dst_path.parent.mkdir(parents=True, exist_ok=True) + + result = convert_file(src_path, dst_path, space, gitbook_root) + dst_path.write_text(result, encoding="utf-8") + converted += 1 + print(f" ✓ {rel} → {dst_rel}") + + print(f"\nConverted: {converted}, Skipped: {skipped}") + + # Copy referenced assets + gitbook_assets = gitbook_root / ".gitbook" / "assets" + if gitbook_assets.is_dir(): + referenced = collect_referenced_assets(gitbook_root) + src_dir = starlight_docs.parents[2] # up to src/ + asset_dst = src_dir / "assets" / space + asset_dst.mkdir(parents=True, exist_ok=True) + + copied = 0 + for original_name, safe_name in sorted(referenced.items()): + asset_src = gitbook_assets / original_name + if asset_src.exists(): + dest = asset_dst / safe_name + if not dest.exists(): + shutil.copy2(asset_src, dest) + copied += 1 + print(f"Assets copied: {copied} (of {len(referenced)} referenced)") + + +if __name__ == "__main__": + main() diff --git a/scripts/fix-external-urls.py b/scripts/fix-external-urls.py new file mode 100755 index 0000000..fc4b88e --- /dev/null +++ b/scripts/fix-external-urls.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python3 +"""Convert hardcoded https://docs.warp.dev/ URLs to internal links.""" +import os, re + +docs_dir = 'src/content/docs' + +# Build valid internal paths +valid_paths = set() +for root, dirs, files in os.walk(docs_dir): + for f in files: + if not f.endswith('.mdx'): continue + rel = os.path.relpath(os.path.join(root, f), docs_dir) + slug = '/' + rel.replace('.mdx', '/').replace('/index/', '/') + if slug == '/index/': slug = '/' + valid_paths.add(slug.rstrip('/')) + +# Old gitbook path -> new docs path mapping +PATH_REMAPPING = { + '/agent-platform/warp-agents/agent-profiles-permissions': '/agent-platform/capabilities/agent-profiles-permissions', + '/agent-platform/warp-agents/skills': '/agent-platform/capabilities/skills', + '/agent-platform/warp-agents/planning': '/agent-platform/capabilities/planning', + '/agent-platform/warp-agents/task-lists': '/agent-platform/capabilities/task-lists', + '/agent-platform/warp-agents/model-choice': '/agent-platform/capabilities/model-choice', + '/agent-platform/warp-agents/rules': '/agent-platform/capabilities/rules', + '/agent-platform/warp-agents/full-terminal-use': '/agent-platform/capabilities/full-terminal-use', + '/agent-platform/warp-agents/computer-use': '/agent-platform/capabilities/computer-use', + '/agent-platform/warp-agents/codebase-context': '/agent-platform/capabilities/codebase-context', + '/agent-platform/warp-agents/web-search': '/agent-platform/capabilities/web-search', + '/agent-platform/warp-agents/mcp': '/agent-platform/capabilities/mcp', + '/agent-platform/warp-agents/slash-commands': '/agent-platform/capabilities/slash-commands', + '/agent-platform/warp-agents/agent-notifications': '/agent-platform/capabilities/agent-notifications', + '/agent-platform/warp-agents/active-ai': '/agent-platform/local-agents/active-ai', + '/agent-platform/warp-agents/code-diffs': '/agent-platform/local-agents/code-diffs', + '/agent-platform/warp-agents/session-sharing': '/agent-platform/local-agents/session-sharing', + '/agent-platform/warp-agents/cloud-conversations': '/agent-platform/local-agents/cloud-conversations', + '/agent-platform/warp-agents/interactive-code-review': '/agent-platform/local-agents/interactive-code-review', + '/agent-platform/warp-agents': '/agent-platform/local-agents/overview', + '/agent-platform/warp-agents/interacting-with-agents': '/agent-platform/local-agents/interacting-with-agents', + '/agent-platform/warp-agents/interacting-with-agents/terminal-and-agent-modes': '/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes', + '/agent-platform/local-agents/interacting-with-agents/agent-modality': '/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes', + '/agent-platform/warp-agents/interacting-with-agents/conversation-forking': '/agent-platform/local-agents/interacting-with-agents/conversation-forking', + '/agent-platform/warp-agents/interacting-with-agents/voice': '/agent-platform/local-agents/interacting-with-agents/voice', + '/agent-platform/warp-agents/agent-context': '/agent-platform/local-agents/agent-context', + '/agent-platform/warp-agents/agent-context/blocks-as-context': '/agent-platform/local-agents/agent-context/blocks-as-context', + '/agent-platform/warp-agents/agent-context/images-as-context': '/agent-platform/local-agents/agent-context/images-as-context', + '/agent-platform/warp-agents/agent-context/urls-as-context': '/agent-platform/local-agents/agent-context/urls-as-context', + '/agent-platform/warp-agents/agent-context/selection-as-context': '/agent-platform/local-agents/agent-context/selection-as-context', + '/agent-platform/warp-agents/agent-context/using-to-add-context': '/agent-platform/local-agents/agent-context/using-to-add-context', + '/agent-platform/third-party-agents': '/agent-platform/cli-agents/overview', + '/agent-platform/cloud-agents/cloud-agents-overview': '/agent-platform/cloud-agents/overview', + '/warp/code/code-review': '/code/code-review', + '/warp/code/git-worktrees': '/code/git-worktrees', + '/warp/knowledge-and-collaboration/warp-drive/agent-mode-context': '/knowledge-and-collaboration/warp-drive/agent-mode-context', + '/warp/terminal/windows/vertical-tabs': '/terminal/windows/vertical-tabs', + '/guides': '/university', + '/guides/integrations/how-to-set-up-claude-code': '/university/integrations/how-to-set-up-claude-code', + '/guides/integrations/how-to-set-up-codex-cli': '/university/integrations/how-to-set-up-codex-cli', + '/guides/integrations/how-to-set-up-gemini-cli': '/university/integrations/how-to-set-up-gemini-cli', + '/guides/integrations/how-to-set-up-opencode': '/university/integrations/how-to-set-up-opencode', + '/knowledge-and-collaboration/rules': '/agent-platform/capabilities/rules', + '/knowledge-and-collaboration/mcp': '/agent-platform/capabilities/mcp', + '/code/codebase-context': '/agent-platform/capabilities/codebase-context', + '/getting-started/installation-and-setup': '/getting-started/quickstart/installation-and-setup', + '/getting-started/keyboard-shortcuts.md': '/getting-started/keyboard-shortcuts', + '/support-and-community/plans-and-billing/plans-and-pricing': '/support-and-community/plans-and-billing/plans-pricing-refunds', + '/reference/api-and-sdk/agent': '/reference/api-and-sdk', + '/reference/cli/cli': '/reference/cli', + '/reference/cli/mcp-for-cloud-agents': '/reference/cli/mcp-servers', + # Additional remappings discovered during the 2026-04-29 sync. + '/warp/code/code-editor': '/code/code-editor', + '/warp/code/code-editor/file-tree': '/code/code-editor/file-tree', + '/warp/code/code-editor/code-editor-vim-keybindings': '/code/code-editor/code-editor-vim-keybindings', + '/warp/code/code-editor/find-and-replace': '/code/code-editor/find-and-replace', + '/warp/code/code-editor/language-server-protocol': '/code/code-editor/language-server-protocol', + '/warp/code/overview': '/code/overview', + '/warp/code/ssh-feature-support': '/code/ssh-feature-support', + '/warp/getting-started': '/getting-started/quickstart/installation-and-setup', + '/warp/getting-started/installation-and-setup': '/getting-started/quickstart/installation-and-setup', + '/warp/getting-started/coding-in-warp': '/getting-started/quickstart/coding-in-warp', + '/warp/getting-started/customizing-warp': '/getting-started/quickstart/customizing-warp', + '/warp/getting-started/migrate-to-warp': '/getting-started/migrate-to-warp', + '/warp/getting-started/keyboard-shortcuts': '/getting-started/keyboard-shortcuts', + '/warp/getting-started/supported-shells': '/getting-started/supported-shells', + '/warp/getting-started/what-is-warp': '/', + '/warp/getting-started/quickstart': '/quickstart', + '/warp/terminal/windows/tab-configs': '/terminal/windows/tab-configs', + '/warp/terminal/windows/configurable-toolbar': '/terminal/windows/configurable-toolbar', + '/warp/terminal/settings': '/terminal/settings', + '/warp/terminal/settings/all-settings': '/terminal/settings/all-settings', + '/warp/knowledge-and-collaboration/admin-panel': '/knowledge-and-collaboration/admin-panel', + '/warp/knowledge-and-collaboration/warp-drive': '/knowledge-and-collaboration/warp-drive', + '/agent-platform/cli-agents': '/agent-platform/cli-agents/overview', + '/guides/mcp-servers/github-mcp-summarizing-open-prs-and-creating-gh-issues': '/university/mcp-servers/github-mcp-summarizing-open-prs-and-creating-gh-issues', + '/guides/mcp-servers/sentry-mcp-fix-sentry-error-in-empower-website': '/university/mcp-servers/sentry-mcp-fix-sentry-error-in-empower-website', + '/guides/mcp-servers/linear-mcp-retrieve-issue-data': '/university/mcp-servers/linear-mcp-retrieve-issue-data', + '/guides/mcp-servers/puppeteer-mcp-scraping-amazon-web-reviews': '/university/mcp-servers/puppeteer-mcp-scraping-amazon-web-reviews', + '/guides/mcp-servers/context7-mcp-update-astro-project-with-best-practices': '/university/mcp-servers/context7-mcp-update-astro-project-with-best-practices', +} + +stats = [0, 0, 0] # total, converted, remapped + +def replace_url(m): + full_url = m.group(0) + url_path = m.group(1) + fragment = m.group(2) or '' + stats[0] += 1 + + clean_path = url_path.rstrip('/') + + if clean_path in valid_paths: + stats[1] += 1 + return clean_path + '/' + fragment + + new_path = PATH_REMAPPING.get(clean_path) + if new_path and new_path.rstrip('/') in valid_paths: + stats[2] += 1 + return new_path + '/' + fragment + + return full_url + +for root, dirs, files in os.walk(docs_dir): + for f in files: + if not f.endswith('.mdx'): continue + if 'changelog' in root: continue + + path = os.path.join(root, f) + content = open(path).read() + + new_content = re.sub( + r'https://docs\.warp\.dev(/[^)\s"#]*)(#[^)\s"]*)?', + replace_url, + content + ) + + if new_content != content: + open(path, 'w').write(new_content) + +print(f"Total external URLs found: {stats[0]}") +print(f"Converted (direct match): {stats[1]}") +print(f"Converted (remapped): {stats[2]}") +print(f"Remaining unconverted: {stats[0] - stats[1] - stats[2]}") diff --git a/scripts/generate-og-api.mjs b/scripts/generate-og-api.mjs new file mode 100644 index 0000000..984d63f --- /dev/null +++ b/scripts/generate-og-api.mjs @@ -0,0 +1,60 @@ +// One-shot script to render public/assets/og/api.png — the social-card image +// (1200×630) used by /api's og:image and twitter:image meta tags. +// +// Run with: node scripts/generate-og-api.mjs +// +// We construct the SVG inline so the Warp wordmark uses the same path data as +// src/assets/warp-logo-dark.svg (no font dependency on the social scraper). +// Sharp rasterizes the SVG to a PNG that's safe to embed everywhere +// (Facebook/Twitter/LinkedIn don't reliably accept SVG og:image). +import { mkdirSync } from 'node:fs'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import sharp from 'sharp'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const outPath = resolve(__dirname, '../public/assets/og/api.png'); +mkdirSync(dirname(outPath), { recursive: true }); + +// Warp wordmark paths copied verbatim from src/assets/warp-logo-dark.svg. +// Two `M…Z` mark paths and one wordmark path. viewBox "91 26 582 135". +const WARP_LOGO = ` + + + + + +`; + +// 1200×630 OG card. The logo is centered horizontally, with subtitle text +// rendered as flat using a generic sans-serif that maps reliably across +// scraper-side renderers. Warp's accent blue underlines the wordmark. +const svg = ` + + + + + + + + + + ${WARP_LOGO} + + + + + + Oz Agent API Reference + + + Create and manage cloud agent runs, schedules, and more. + + + DOCS.WARP.DEV + + +`; + +await sharp(Buffer.from(svg)).png().toFile(outPath); +console.log(`Wrote ${outPath}`); diff --git a/scripts/merge_seo_redirects.py b/scripts/merge_seo_redirects.py new file mode 100644 index 0000000..68bf2d6 --- /dev/null +++ b/scripts/merge_seo_redirects.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python3 +"""Merge seo/static-assets redirects on top of main's vercel.json. + +Run this from the repo root after: + git checkout seo/static-assets + git merge --no-commit --no-ff origin/main + git checkout --theirs vercel.json # take main's vercel.json into worktree + +This script then layers seo's net-new redirects on top, with three rules: + +- Group A: drop. seo had 8 entries `/university/X[/]? -> /university/`. Those + destinations no longer exist on main; main's catch-all + `/university/(.*) -> /guides/$1` plus its 13 explicit directory entries + supersede them. + +- Group B: rewrite the destination. seo has 107 entries `/old-path -> + /university/` whose destinations are now gone. Build a map from main's + 67 explicit `/university/X -> /guides//X` redirects and use it to + rewrite the destination. 4 destinations have no explicit main mapping + (newly-ported guides PR #56 added); supply hardcoded fallbacks. + +- Group C: keep as-is. seo has 768 entries that don't touch /university/ on + either side - the bulk of the SEO work (sitemap-only, GSC, trailing-slash + variants, getting-started/features renames, agent-platform self-hosting + renames, etc.). + +The catch-all `/university/(.*) -> /guides/$1` is moved to the very end of +the resulting array so it can't shadow more specific rules. + +Output: vercel.json is overwritten in place with 2-space indent and a +trailing newline, matching the existing file's formatting. +""" + +from __future__ import annotations + +import json +import subprocess +import sys +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[1] +VERCEL_JSON = REPO_ROOT / "vercel.json" + +# 4 destinations on seo that do not have an explicit /university/X -> /guides/... +# mapping in main, because PR #56 ported these as brand-new guides rather than +# moving an existing university page. Hardcode the canonical /guides/ path. +HARDCODED_FALLBACKS: dict[str, str] = { + "/university/developer-workflows/power-user/how-to-set-up-self-serve-data-analytics-with-skills": "/guides/configuration/how-to-set-up-self-serve-data-analytics-with-skills/", + "/university/developer-workflows/power-user/how-to-set-up-self-serve-data-analytics-with-skills/": "/guides/configuration/how-to-set-up-self-serve-data-analytics-with-skills/", + "/university/developer-workflows/warp-for-product-managers": "/guides/agent-workflows/warp-for-product-managers/", + "/university/developer-workflows/warp-for-product-managers/": "/guides/agent-workflows/warp-for-product-managers/", +} + +CATCHALL_SOURCE = "/university/(.*)" + + +def load_main_redirects() -> list[dict]: + """vercel.json in the worktree is currently main's version (taken via --theirs).""" + return json.loads(VERCEL_JSON.read_text())["redirects"] + + +def load_seo_redirects() -> list[dict]: + """Pull seo/static-assets's vercel.json from git directly so we don't lose info.""" + raw = subprocess.check_output( + ["git", "show", "seo/static-assets:vercel.json"], cwd=REPO_ROOT, text=True + ) + return json.loads(raw)["redirects"] + + +def build_univ_to_guides_map(main_redirects: list[dict]) -> dict[str, str]: + """Return a dict of /university/X (no trailing slash) -> /guides///. + + Only includes entries where main maps an explicit /university/X to a /guides/ + destination. The catch-all and directory-fallback entries are excluded so that + rewriting prefers a specific destination when one exists. + """ + mapping: dict[str, str] = {} + for r in main_redirects: + s = r["source"].rstrip("/") + d = r["destination"] + if ( + s.startswith("/university/") + and d.startswith("/guides/") + and d != "/guides/" # skip directory-fallback entries + and "(.*)" not in s # skip catch-all + ): + mapping[s] = d + return mapping + + +def classify_and_rewrite_seo_only( + seo_only: list[dict], univ_map: dict[str, str] +) -> tuple[list[dict], dict[str, int]]: + """Walk seo_only entries; drop/rewrite/keep per the plan.""" + kept: list[dict] = [] + counters = {"group_a_dropped": 0, "group_b_rewritten": 0, "group_c_kept": 0, + "rewrite_self_dropped": 0, "rewrite_unmapped_kept": 0} + for r in seo_only: + s, d = r["source"], r["destination"] + if s.startswith("/university") and d.startswith("/university"): + # Group A - drop, main supersedes. + counters["group_a_dropped"] += 1 + continue + if d.startswith("/university"): + # Group B - rewrite destination. + d_no_slash = d.rstrip("/") + new_dest = univ_map.get(d_no_slash) or HARDCODED_FALLBACKS.get(d) or HARDCODED_FALLBACKS.get(d_no_slash) + if new_dest is None: + # Should not happen given audit, but fail loudly if it does + print(f"WARN: no /university->/guides mapping for destination {d!r} (source {s!r}); dropping", file=sys.stderr) + counters["rewrite_unmapped_kept"] += 1 + continue + if s.rstrip("/") == new_dest.rstrip("/"): + # Source and rewritten destination collapse - drop self-redirect. + counters["rewrite_self_dropped"] += 1 + continue + kept.append({**r, "destination": new_dest}) + counters["group_b_rewritten"] += 1 + continue + # Group C - keep as-is. + kept.append(r) + counters["group_c_kept"] += 1 + return kept, counters + + +def merge() -> None: + main_redirects = load_main_redirects() + seo_redirects = load_seo_redirects() + + main_pairs = {(r["source"], r["destination"]) for r in main_redirects} + seo_pairs = {(r["source"], r["destination"]) for r in seo_redirects} + seo_only_pairs = seo_pairs - main_pairs + + # Preserve order from seo: walk seo_redirects, keep only the entries whose + # (source, destination) pair is in seo_only_pairs. + seen: set[tuple[str, str]] = set() + seo_only: list[dict] = [] + for r in seo_redirects: + key = (r["source"], r["destination"]) + if key in seo_only_pairs and key not in seen: + seo_only.append(r) + seen.add(key) + + print(f"main entries: {len(main_redirects)}") + print(f"seo entries: {len(seo_redirects)}") + print(f"seo-only entries: {len(seo_only)}") + + univ_map = build_univ_to_guides_map(main_redirects) + print(f"main /univ->/guides explicit mappings: {len(univ_map)}") + + seo_kept, counters = classify_and_rewrite_seo_only(seo_only, univ_map) + print(f"\nGroup A dropped (seo /university/* -> /university/*): {counters['group_a_dropped']}") + print(f"Group B rewritten (seo /old -> /university/X => /guides/Y): {counters['group_b_rewritten']}") + print(f"Group C kept (seo non-university entries): {counters['group_c_kept']}") + print(f"Rewrites collapsed to self-redirect (dropped): {counters['rewrite_self_dropped']}") + if counters["rewrite_unmapped_kept"]: + print(f"WARN: rewrites with no mapping (dropped): {counters['rewrite_unmapped_kept']}") + + # Pull main's catch-all aside; we want it to stay at the very end after appending seo entries. + main_no_catchall: list[dict] = [] + catchall: dict | None = None + for r in main_redirects: + if r["source"] == CATCHALL_SOURCE: + catchall = r + else: + main_no_catchall.append(r) + if catchall is None: + raise RuntimeError(f"Expected catch-all {CATCHALL_SOURCE!r} in main redirects; not found") + + # Final order: main's explicit redirects (in main's order), then seo additions + # (in seo's order, deduped against main and against itself), then the catch-all. + final: list[dict] = list(main_no_catchall) + final_pairs: set[tuple[str, str]] = {(r["source"], r["destination"]) for r in final} + for r in seo_kept: + key = (r["source"], r["destination"]) + if key in final_pairs: + continue + final.append(r) + final_pairs.add(key) + # Catch-all goes last so it can't shadow more specific rules. + final.append(catchall) + + print(f"\nfinal redirect count: {len(final)}") + + # Preserve formatting: load full top-level dict, replace redirects, write with 2-space indent + trailing newline. + full = json.loads(VERCEL_JSON.read_text()) + full["redirects"] = final + VERCEL_JSON.write_text(json.dumps(full, indent=2) + "\n") + print(f"wrote {VERCEL_JSON}") + + +if __name__ == "__main__": + merge() diff --git a/scripts/migrate-all.py b/scripts/migrate-all.py new file mode 100755 index 0000000..cad2a2b --- /dev/null +++ b/scripts/migrate-all.py @@ -0,0 +1,694 @@ +#!/usr/bin/env python3 +"""Master migration: convert ALL GitBook content to Astro Starlight. + +Handles the structural remapping between repos: + - gitbook/docs/warp/* → docs top-level (terminal/, code/, getting-started/, knowledge-and-collaboration/) + - gitbook/docs/agent-platform/warp-agents/* → split into capabilities/ and local-agents/ + - gitbook/docs/agent-platform/cli-agents/* → agent-platform/cli-agents/ + - gitbook/guides/* → university/ + - README.md → index.mdx everywhere + +Usage: + python scripts/migrate-all.py /path/to/gitbook +""" + +import json +import re +import shutil +import sys +from pathlib import Path + +# Import conversion functions from existing script +sys.path.insert(0, str(Path(__file__).parent)) +from importlib.machinery import SourceFileLoader +convert_mod = SourceFileLoader("convert_gitbook", str(Path(__file__).parent / "convert-gitbook.py")).load_module() + +# Re-export all conversion functions +parse_frontmatter = convert_mod.parse_frontmatter +build_frontmatter = convert_mod.build_frontmatter +strip_first_h1 = convert_mod.strip_first_h1 +convert_hints = convert_mod.convert_hints +convert_embeds = convert_mod.convert_embeds +convert_tabs = convert_mod.convert_tabs +convert_code_blocks = convert_mod.convert_code_blocks +convert_steppers = convert_mod.convert_steppers +strip_gitbook_card_tables = convert_mod.strip_gitbook_card_tables +strip_gitbook_content_refs = convert_mod.strip_gitbook_content_refs +convert_figures = convert_mod.convert_figures +convert_inline_images = convert_mod.convert_inline_images +convert_html_comments = convert_mod.convert_html_comments +strip_custom_anchors = convert_mod.strip_custom_anchors +convert_horizontal_rules = convert_mod.convert_horizontal_rules +sanitize_html_tables = convert_mod.sanitize_html_tables +fix_html_void_elements = convert_mod.fix_html_void_elements +convert_autolinks = convert_mod.convert_autolinks +inject_imports = convert_mod.inject_imports +sanitize_asset_filename = convert_mod.sanitize_asset_filename +KEEP_FRONTMATTER_KEYS = convert_mod.KEEP_FRONTMATTER_KEYS + +# --------------------------------------------------------------------------- +# Path mapping configuration +# --------------------------------------------------------------------------- + +# warp-agents files that go to capabilities/ +CAPABILITIES_FILES = { + "agent-profiles-permissions", "skills", "planning", "task-lists", + "model-choice", "rules", "full-terminal-use", "computer-use", + "codebase-context", "web-search", "mcp", "slash-commands", + "agent-notifications", +} + +# warp-agents files that go to local-agents/ +LOCAL_AGENTS_FILES = { + "active-ai", "code-diffs", "session-sharing", "cloud-conversations", + "interactive-code-review", +} + +# warp-agents/README.md → local-agents/overview.mdx +# warp-agents/capabilities-overview.md → capabilities/index.mdx +# warp-agents/interacting-with-agents/* → local-agents/interacting-with-agents/* +# warp-agents/agent-context/* → local-agents/agent-context/* + +# Rename map for specific files +RENAME_MAP = { + "warp-agents/README.md": "local-agents/overview.mdx", + "warp-agents/capabilities-overview.md": "capabilities/index.mdx", + # The legacy `agent-modality.mdx` file was renamed to + # `terminal-and-agent-modes.mdx` in the 2026-04-29 sync to align with + # AGENTS.md style guidance ("Agent Modality" was an internal name). + "warp-agents/interacting-with-agents/terminal-and-agent-modes.md": "local-agents/interacting-with-agents/terminal-and-agent-modes.mdx", +} + +# Per-space rename map for files that the docs repo intentionally moved away +# from the gitbook layout. Values are paths relative to the docs root +# (`src/content/docs/`). +WARP_RENAME_MAP = { + # Quickstart pages live under getting-started/quickstart/ in the docs + # repo even though gitbook keeps them flat under getting-started/. + "getting-started/coding-in-warp.md": "getting-started/quickstart/coding-in-warp.mdx", + "getting-started/customizing-warp.md": "getting-started/quickstart/customizing-warp.mdx", + "getting-started/installation-and-setup.md": "getting-started/quickstart/installation-and-setup.mdx", + # Top-level landing pages were renamed during the original migration. + "getting-started/quickstart.md": "quickstart.mdx", + "README.md": "index.mdx", +} + +# Per-space skip set for orphaned/duplicate gitbook files that the docs repo +# intentionally drops. Values are gitbook-relative paths. +SKIP_PATHS = { + "support-and-community": { + # Duplicate of logging-out-and-uninstalling.md kept around in gitbook + # only as a redirect target. + "troubleshooting-and-support/uninstalling-warp.md", + }, +} + + +def compute_docs_url_path(gitbook_space: str, gitbook_rel: str) -> str: + """Given a gitbook space and relative file path, compute the URL path in the docs site. + + This is used for link rewriting. Returns a URL path like /agent-platform/capabilities/skills/ + """ + # Apply the structural remapping + dest = map_gitbook_path(gitbook_space, gitbook_rel) + # Convert to URL path + url = dest.replace(".mdx", "/") + if url.endswith("/index/"): + url = url[:-6] # /foo/index/ -> /foo/ + if not url.startswith("/"): + url = "/" + url + if not url.endswith("/"): + url += "/" + return url + + +def map_gitbook_path(space: str, rel_path: str) -> str: + """Map a gitbook file path to its docs destination path. + + Args: + space: One of 'warp', 'agent-platform', 'reference', 'support-and-community', + 'enterprise', 'changelog', 'guides' + rel_path: Path relative to the space root (e.g. 'terminal/blocks/block-basics.md') + + Returns: + Path relative to src/content/docs/ (e.g. 'terminal/blocks/block-basics.mdx') + """ + p = rel_path + + if space == "warp": + # warp/ content strips the prefix and goes to top-level sections. + # First check the docs-specific rename map for files that landed at + # different paths during the original migration (e.g. quickstart pages + # were folded into getting-started/quickstart/). + if p in WARP_RENAME_MAP: + return WARP_RENAME_MAP[p] + # Otherwise the rel_path is already relative to warp/, so just convert + # the extension below. + pass + elif space == "agent-platform": + # Handle warp-agents/ split + if p.startswith("warp-agents/"): + inner = p[len("warp-agents/"):] + # Check explicit rename map first. RENAME_MAP values are paths + # relative to the agent-platform/ root, so we still need to add + # the agent-platform/ prefix and then return early before the + # README.md → index.mdx normalization runs. + if p in RENAME_MAP: + return "agent-platform/" + RENAME_MAP[p] + # interacting-with-agents/* → local-agents/interacting-with-agents/* + if inner.startswith("interacting-with-agents/"): + p = "local-agents/" + inner + # agent-context/* → local-agents/agent-context/* + elif inner.startswith("agent-context/"): + p = "local-agents/" + inner + else: + stem = inner.replace(".md", "").replace("/README", "") + if stem in CAPABILITIES_FILES: + p = "capabilities/" + inner + elif stem in LOCAL_AGENTS_FILES: + p = "local-agents/" + inner + else: + # Default to capabilities for unknown + p = "capabilities/" + inner + p = "agent-platform/" + p + else: + p = "agent-platform/" + p + elif space == "guides": + p = "university/" + p + else: + # reference, support-and-community, enterprise, changelog + p = space + "/" + p + + # README.md → index.mdx + if p.endswith("/README.md"): + p = p[:-len("/README.md")] + "/index.mdx" + elif p == "README.md": + p = "index.mdx" + else: + p = p[:-3] + ".mdx" + + return p + + +def map_asset_space(space: str) -> str: + """Map a gitbook space to an asset directory name.""" + if space == "warp": + return "terminal" # warp assets go to terminal/ + elif space == "guides": + return "university" + else: + return space + + +# --------------------------------------------------------------------------- +# Enhanced link rewriting +# --------------------------------------------------------------------------- + +# Cross-space link patterns that need special handling +CROSS_SPACE_LINK_MAP = { + # From warp space, links to agent-platform + "../agent-platform/": "/agent-platform/", + # From agent-platform, links to warp + "../warp/": "/", +} + + +def convert_links_enhanced(content: str, file_rel_dir: str, space: str) -> str: + """Rewrite relative .md links to absolute URL paths with structural remapping.""" + + def _rewrite_link(m): + text = m.group(1) + href = m.group(2) + fragment = "" + + # Skip external, absolute, anchor-only, and mailto links + if href.startswith(("http://", "https://", "/", "#", "mailto:")): + return m.group(0) + + # Separate fragment + if "#" in href: + href, fragment = href.split("#", 1) + fragment = "#" + fragment + + if not href: + return f"[{text}](#{fragment[1:]})" if fragment else m.group(0) + + # Handle cross-space links (../agent-platform/, ../warp/, etc.) + cross_space = None + cross_rel = href + for prefix, url_prefix in CROSS_SPACE_LINK_MAP.items(): + if href.startswith(prefix): + cross_rel = href[len(prefix):] + if prefix.startswith("../agent-platform"): + cross_space = "agent-platform" + elif prefix.startswith("../warp"): + cross_space = "warp" + break + + if cross_space: + # Resolve the cross-space link + parts = cross_rel.split("/") + normalised = [p for p in parts if p and p != "."] + resolved = [] + for p in normalised: + if p == "..": + if resolved: + resolved.pop() + else: + resolved.append(p) + cross_file = "/".join(resolved) + if not cross_file.endswith(".md"): + if not cross_file: + cross_file = "README.md" + else: + cross_file += ".md" if "." not in cross_file.split("/")[-1] else "" + url = compute_docs_url_path(cross_space, cross_file) + return f"[{text}]({url}{fragment})" + + # Normalise the path relative to the current file's directory + parts = ((file_rel_dir + "/" + href) if file_rel_dir else href).split("/") + normalised = [] + for p in parts: + if p == "..": + if normalised: + normalised.pop() + elif p and p != ".": + normalised.append(p) + rel = "/".join(normalised) + + # Compute URL from the resolved gitbook-relative path + if rel.endswith(".md"): + url = compute_docs_url_path(space, rel) + else: + # Treat as directory → README.md + readme = (rel + "/README.md") if rel else "README.md" + url = compute_docs_url_path(space, readme) + + return f"[{text}]({url}{fragment})" + + # Negative lookbehind to skip image links ![alt](url) + return re.sub(r"(? str: + """Compute relative path from a doc file to its asset directory.""" + try: + rel_to_content = dst_path.relative_to(docs_root / "src" / "content" / "docs") + except ValueError: + return "../../../../assets/terminal/" + + # Determine which asset directory to use based on the content path + parts = rel_to_content.parts + if len(parts) > 0 and parts[0] == "agent-platform": + asset_dir = "agent-platform" + elif len(parts) > 0 and parts[0] == "reference": + asset_dir = "reference" + elif len(parts) > 0 and parts[0] == "support-and-community": + asset_dir = "support-and-community" + elif len(parts) > 0 and parts[0] == "university": + asset_dir = "university" + elif len(parts) > 0 and parts[0] == "enterprise": + asset_dir = "enterprise" + else: + asset_dir = "terminal" + + depth = len(rel_to_content.parent.parts) + # From content/docs/ up to src/: 2 + depth (content/docs = 2 levels) + ups = 2 + depth + return "../" * ups + f"assets/{asset_dir}/" + + +def convert_file_enhanced( + src_path: Path, + dst_path: Path, + space: str, + gitbook_space_root: Path, + docs_root: Path, +) -> str: + """Convert a single GitBook markdown file to Starlight MDX with enhanced link rewriting.""" + content = src_path.read_text(encoding="utf-8") + + # Determine relative directory within the space + try: + file_rel = src_path.relative_to(gitbook_space_root) + except ValueError: + file_rel = Path(src_path.name) + file_rel_dir = str(file_rel.parent) if str(file_rel.parent) != "." else "" + + # Compute asset prefix from destination path + rel_asset_prefix = compute_rel_asset_prefix(dst_path, docs_root) + + # 1. Parse and rebuild frontmatter + fm, body = parse_frontmatter(content) + for key in list(fm.keys()): + if key not in KEEP_FRONTMATTER_KEYS: + del fm[key] + new_fm = build_frontmatter(fm, body) + body = strip_first_h1(body) + + # 2. Apply transforms (order matters) + body = convert_hints(body) + body = convert_embeds(body) + body = convert_tabs(body) + body = convert_code_blocks(body) + body = convert_steppers(body) + body = strip_gitbook_card_tables(body) + body = strip_gitbook_content_refs(body) + body = convert_figures(body, rel_asset_prefix) + body = convert_inline_images(body, rel_asset_prefix) + body = convert_links_enhanced(body, file_rel_dir, space) + body = convert_html_comments(body) + body = strip_custom_anchors(body) + body = convert_horizontal_rules(body) + body = sanitize_html_tables(body) + body = fix_html_void_elements(body) + body = convert_autolinks(body) + + # 3. Reassemble + result = new_fm + "\n" + body + + # 4. Inject MDX imports + result = inject_imports(result) + + # 5. Clean up excessive blank lines + result = re.sub(r"\n{3,}", "\n\n", result) + + if not result.endswith("\n"): + result += "\n" + + return result + + +# --------------------------------------------------------------------------- +# Asset collection and copying +# --------------------------------------------------------------------------- + + +def copy_space_assets(gitbook_space_root: Path, asset_dir: Path) -> int: + """Copy all referenced assets from a gitbook space to the docs asset directory.""" + gitbook_assets = gitbook_space_root / ".gitbook" / "assets" + if not gitbook_assets.is_dir(): + return 0 + + asset_dir.mkdir(parents=True, exist_ok=True) + + # Collect all referenced asset filenames + referenced = {} + for md_file in gitbook_space_root.rglob("*.md"): + if md_file.name == "SUMMARY.md": + continue + try: + content = md_file.read_text(encoding="utf-8") + except Exception: + continue + for m in re.finditer(r'\.gitbook/assets/([^")\s]+)', content): + original = m.group(1).strip() + if original: + referenced[original] = sanitize_asset_filename(original) + + # Also copy any unreferenced assets (they might be referenced by converted content) + for asset_file in gitbook_assets.iterdir(): + if asset_file.is_file(): + name = asset_file.name + if name not in referenced: + referenced[name] = sanitize_asset_filename(name) + + copied = 0 + for original_name, safe_name in sorted(referenced.items()): + asset_src = gitbook_assets / original_name + if asset_src.exists(): + dest = asset_dir / safe_name + if not dest.exists() or asset_src.stat().st_size != dest.stat().st_size: + shutil.copy2(asset_src, dest) + copied += 1 + + return copied + + +# --------------------------------------------------------------------------- +# Redirect extraction +# --------------------------------------------------------------------------- + + +def parse_gitbook_yaml_redirects(yaml_path: Path) -> dict: + """Parse redirects from a .gitbook.yaml file. Returns dict of source->target.""" + if not yaml_path.exists(): + return {} + + content = yaml_path.read_text(encoding="utf-8") + redirects = {} + in_redirects = False + + for line in content.split("\n"): + stripped = line.strip() + if stripped == "redirects:": + in_redirects = True + continue + if in_redirects: + if not line.startswith(" ") and not line.startswith("\t") and stripped and not stripped.startswith("#"): + break + m = re.match(r"\s+([^#:][^:]*?):\s+(.+)", line) + if m: + source = m.group(1).strip() + target = m.group(2).strip() + redirects[source] = target + + return redirects + + +def transform_redirect_target(space: str, target: str) -> str: + """Transform a gitbook redirect target to a docs URL path.""" + # Remove .md extension and README + t = target + if t.endswith(".md"): + t = t[:-3] + t = re.sub(r"/README$", "", t) + if t == "README": + t = "" + + # Handle fragment + fragment = "" + if "#" in t: + t, fragment = t.split("#", 1) + fragment = "#" + fragment + + # Apply space prefix and structural remapping + if space == "warp": + # warp space content goes to top level (no prefix) + url = "/" + t if t else "/" + elif space == "agent-platform": + # Handle warp-agents/ split + if t.startswith("warp-agents/"): + inner = t[len("warp-agents/"):] + stem = inner.split("/")[0] if "/" in inner else inner + if stem in CAPABILITIES_FILES: + url = "/agent-platform/capabilities/" + inner + elif stem in LOCAL_AGENTS_FILES: + url = "/agent-platform/local-agents/" + inner + elif inner.startswith("interacting-with-agents"): + url = "/agent-platform/local-agents/" + inner + elif inner.startswith("agent-context"): + url = "/agent-platform/local-agents/" + inner + elif inner == "" or inner == "README": + url = "/agent-platform/local-agents/overview" + else: + url = "/agent-platform/capabilities/" + inner + elif t.startswith("cli-agents/"): + url = "/agent-platform/" + t + else: + url = "/agent-platform/" + t if t else "/agent-platform/" + elif space == "guides": + url = "/university/" + t if t else "/university/" + else: + url = "/" + space + "/" + t if t else "/" + space + "/" + + # Clean up + url = url.rstrip("/") + "/" + while "//" in url: + url = url.replace("//", "/") + + return url + fragment + + +def generate_all_redirects(gitbook_root: Path) -> list: + """Parse all .gitbook.yaml files and generate vercel.json redirect entries.""" + spaces = { + "warp": gitbook_root / "docs" / "warp", + "agent-platform": gitbook_root / "docs" / "agent-platform", + "reference": gitbook_root / "docs" / "reference", + "support-and-community": gitbook_root / "docs" / "support-and-community", + "enterprise": gitbook_root / "docs" / "enterprise", + "changelog": gitbook_root / "docs" / "changelog", + "guides": gitbook_root / "guides", + } + + all_redirects = [] + seen_sources = set() + + for space_name, space_dir in spaces.items(): + yaml_path = space_dir / ".gitbook.yaml" + raw_redirects = parse_gitbook_yaml_redirects(yaml_path) + + for source, target in raw_redirects.items(): + # Build the full source URL (space prefix) + if space_name == "warp": + full_source = "/" + source + elif space_name == "agent-platform": + full_source = "/agent-platform/" + source + elif space_name == "guides": + full_source = "/university/" + source + else: + full_source = "/" + space_name + "/" + source + + # Clean up source + full_source = full_source.rstrip("/") + while "//" in full_source: + full_source = full_source.replace("//", "/") + + # Transform target + dest = transform_redirect_target(space_name, target) + + # Skip self-redirects + if full_source.rstrip("/") == dest.rstrip("/"): + continue + + if full_source not in seen_sources: + seen_sources.add(full_source) + all_redirects.append({ + "source": full_source, + "destination": dest, + "statusCode": 308, + }) + + return sorted(all_redirects, key=lambda r: r["source"]) + + +# --------------------------------------------------------------------------- +# Main migration +# --------------------------------------------------------------------------- + + +def migrate_space( + gitbook_space_root: Path, + docs_root: Path, + space: str, +) -> tuple[int, int]: + """Migrate all files from a gitbook space. + + Returns (converted_count, asset_count). + """ + starlight_docs = docs_root / "src" / "content" / "docs" + + md_files = sorted( + p for p in gitbook_space_root.rglob("*.md") + if p.name != "SUMMARY.md" and "/_book/" not in str(p) and "/.gitbook/" not in str(p) + ) + + converted = 0 + for src_path in md_files: + rel = str(src_path.relative_to(gitbook_space_root)) + dst_rel = map_gitbook_path(space, rel) + dst_path = starlight_docs / dst_rel + dst_path.parent.mkdir(parents=True, exist_ok=True) + + result = convert_file_enhanced(src_path, dst_path, space, gitbook_space_root, docs_root) + dst_path.write_text(result, encoding="utf-8") + converted += 1 + print(f" ✓ {rel} → {dst_rel}") + + # Copy assets + asset_dir_name = map_asset_space(space) + asset_dir = docs_root / "src" / "assets" / asset_dir_name + asset_count = copy_space_assets(gitbook_space_root, asset_dir) + + return converted, asset_count + + +def main(): + if len(sys.argv) < 2: + print(__doc__) + sys.exit(1) + + gitbook_root = Path(sys.argv[1]).resolve() + docs_root = Path(__file__).parent.parent.resolve() + + if not (gitbook_root / "docs").is_dir(): + print(f"Error: {gitbook_root}/docs is not a directory") + sys.exit(1) + + spaces = [ + ("warp", gitbook_root / "docs" / "warp"), + ("agent-platform", gitbook_root / "docs" / "agent-platform"), + ("reference", gitbook_root / "docs" / "reference"), + ("support-and-community", gitbook_root / "docs" / "support-and-community"), + ("enterprise", gitbook_root / "docs" / "enterprise"), + ("changelog", gitbook_root / "docs" / "changelog"), + ("guides", gitbook_root / "guides"), + ] + + # Also handle the top-level README.md + top_readme = gitbook_root / "docs" / "README.md" + + total_converted = 0 + total_assets = 0 + + for space_name, space_dir in spaces: + if not space_dir.is_dir(): + print(f"\n⚠ Skipping {space_name} (not found: {space_dir})") + continue + print(f"\n{'='*60}") + print(f" Migrating: {space_name}") + print(f"{'='*60}") + converted, assets = migrate_space(space_dir, docs_root, space_name) + total_converted += converted + total_assets += assets + print(f" → {converted} files converted, {assets} assets copied") + + # Convert top-level README.md → index.mdx + if top_readme.exists(): + print(f"\n Converting top-level README.md → index.mdx") + starlight_docs = docs_root / "src" / "content" / "docs" + dst_path = starlight_docs / "index.mdx" + result = convert_file_enhanced( + top_readme, dst_path, "warp", + gitbook_root / "docs", docs_root, + ) + dst_path.write_text(result, encoding="utf-8") + total_converted += 1 + + # Generate redirects + print(f"\n{'='*60}") + print(f" Generating redirects") + print(f"{'='*60}") + redirects = generate_all_redirects(gitbook_root) + + # Read existing vercel.json and merge + vercel_json_path = docs_root / "vercel.json" + if vercel_json_path.exists(): + existing = json.loads(vercel_json_path.read_text(encoding="utf-8")) + else: + existing = {} + + # Keep non-redirect config, replace redirects entirely + existing["redirects"] = redirects + vercel_json_path.write_text( + json.dumps(existing, indent=2) + "\n", + encoding="utf-8", + ) + print(f" → {len(redirects)} redirects written to vercel.json") + + print(f"\n{'='*60}") + print(f" MIGRATION COMPLETE") + print(f" Total files converted: {total_converted}") + print(f" Total assets copied: {total_assets}") + print(f" Total redirects: {len(redirects)}") + print(f"{'='*60}") + + +if __name__ == "__main__": + main() diff --git a/scripts/seo-audit.mjs b/scripts/seo-audit.mjs new file mode 100644 index 0000000..8facf63 --- /dev/null +++ b/scripts/seo-audit.mjs @@ -0,0 +1,260 @@ +#!/usr/bin/env node +/** + * SEO audit script. + * + * Verifies that every page we ship to docs.warp.dev has the same SEO tags + * the legacy GitBook docs emit today (title, description, canonical, robots, + * Open Graph, Twitter, alternate markdown link, apple-touch-icon, etc). + * + * Usage: + * # Audit a built site on disk (run after `npm run build`) + * node scripts/seo-audit.mjs --dist ./dist + * + * # Audit live URLs (handy for spot-checking the legacy GitBook output) + * node scripts/seo-audit.mjs --base https://docs.warp.dev /agent-platform/cloud-agents/oz-web-app /changelog + * + * # Diff between two sources, e.g. legacy vs. our preview deploy + * node scripts/seo-audit.mjs \\ + * --base https://docs.warp.dev \\ + * --compare https://docs-preview.warp.dev \\ + * /agent-platform/cloud-agents/oz-web-app + * + * The script is intentionally dependency-free (uses regex over the raw HTML + * head) so it runs in CI without installing extra packages. + */ +import { readFile } from 'node:fs/promises'; +import path from 'node:path'; + +const DEFAULT_PATHS = [ + '/', + '/quickstart/', + '/agent-platform/', + '/agent-platform/cloud-agents/oz-web-app/', + '/agent-platform/capabilities/skills/', + '/reference/cli/', + '/reference/api-and-sdk/', + '/changelog/', + '/university/', +]; + +/** Tags GitBook produces that we want to keep at parity. */ +const REQUIRED_TAGS = [ + { key: 'title', label: '' }, + { key: 'meta:description', label: 'meta name="description"' }, + { key: 'meta:robots', label: 'meta name="robots"' }, + { key: 'link:canonical', label: 'link rel="canonical"' }, + { key: 'meta:og:title', label: 'meta property="og:title"' }, + { key: 'meta:og:description', label: 'meta property="og:description"' }, + { key: 'meta:og:image', label: 'meta property="og:image"' }, + { key: 'meta:og:url', label: 'meta property="og:url"' }, + { key: 'meta:og:site_name', label: 'meta property="og:site_name"' }, + { key: 'meta:twitter:card', label: 'meta name="twitter:card"' }, + { key: 'meta:twitter:title', label: 'meta name="twitter:title"' }, + { key: 'meta:twitter:description', label: 'meta name="twitter:description"' }, + { key: 'meta:twitter:image', label: 'meta name="twitter:image"' }, + { key: 'meta:apple-mobile-web-app-title', label: 'meta name="apple-mobile-web-app-title"' }, + { key: 'link:apple-touch-icon', label: 'link rel="apple-touch-icon"' }, + { key: 'link:alternate-markdown', label: 'link rel="alternate" type="text/markdown"' }, + { key: 'link:sitemap-or-icon', label: 'link rel="sitemap" or "icon"/"shortcut icon"' }, +]; + +function parseArgs(argv) { + const args = { dist: null, base: null, compare: null, paths: [] }; + for (let i = 0; i < argv.length; i++) { + const arg = argv[i]; + if (arg === '--dist') args.dist = argv[++i]; + else if (arg === '--base') args.base = argv[++i]; + else if (arg === '--compare') args.compare = argv[++i]; + else if (arg === '--help' || arg === '-h') args.help = true; + else args.paths.push(arg); + } + return args; +} + +function extractHead(html) { + const headMatch = html.match(/<head[^>]*>([\s\S]*?)<\/head>/i); + return headMatch ? headMatch[1] : html; +} + +function getTitle(head) { + const m = head.match(/<title[^>]*>([\s\S]*?)<\/title>/i); + return m ? m[1].trim() : null; +} + +function getMeta(head, attr, value) { + // Match either name="x" or property="x" (and either order of attrs). + const re = new RegExp( + `<meta[^>]*(?:${attr}=["']${value}["'][^>]*content=["']([^"']*)["']|content=["']([^"']*)["'][^>]*${attr}=["']${value}["'])[^>]*>`, + 'i', + ); + const m = head.match(re); + return m ? (m[1] ?? m[2]) : null; +} + +function getLink(head, rel, type) { + const typePart = type ? `type=["']${type}["']` : null; + // Try both attribute orders. Astro sometimes emits href before rel. + const patterns = [ + new RegExp( + `<link[^>]*rel=["']${rel}["']${typePart ? `[^>]*${typePart}` : ''}[^>]*href=["']([^"']*)["'][^>]*>`, + 'i', + ), + new RegExp( + `<link[^>]*href=["']([^"']*)["'][^>]*rel=["']${rel}["']${typePart ? `[^>]*${typePart}` : ''}[^>]*>`, + 'i', + ), + ]; + for (const re of patterns) { + const m = head.match(re); + if (m) return m[1]; + } + return null; +} + +function audit(html) { + const head = extractHead(html); + const result = { + 'title': getTitle(head), + 'meta:description': getMeta(head, 'name', 'description'), + 'meta:robots': getMeta(head, 'name', 'robots'), + 'link:canonical': getLink(head, 'canonical'), + 'meta:og:title': getMeta(head, 'property', 'og:title'), + 'meta:og:description': getMeta(head, 'property', 'og:description'), + 'meta:og:image': getMeta(head, 'property', 'og:image'), + 'meta:og:url': getMeta(head, 'property', 'og:url'), + 'meta:og:site_name': getMeta(head, 'property', 'og:site_name'), + 'meta:twitter:card': getMeta(head, 'name', 'twitter:card'), + 'meta:twitter:title': getMeta(head, 'name', 'twitter:title'), + 'meta:twitter:description': getMeta(head, 'name', 'twitter:description'), + 'meta:twitter:image': getMeta(head, 'name', 'twitter:image'), + 'meta:apple-mobile-web-app-title': getMeta(head, 'name', 'apple-mobile-web-app-title'), + 'link:apple-touch-icon': getLink(head, 'apple-touch-icon'), + 'link:alternate-markdown': getLink(head, 'alternate', 'text/markdown'), + 'link:sitemap-or-icon': getLink(head, 'sitemap') ?? getLink(head, 'icon') ?? getLink(head, 'shortcut icon'), + }; + return result; +} + +async function loadFromDist(distRoot, urlPath) { + const trimmed = urlPath.replace(/^\/+|\/+$/g, ''); + const candidates = [ + path.join(distRoot, trimmed, 'index.html'), + path.join(distRoot, trimmed + '.html'), + // Root path + ...(trimmed === '' ? [path.join(distRoot, 'index.html')] : []), + ]; + for (const candidate of candidates) { + try { + return await readFile(candidate, 'utf8'); + } catch { + // Try next candidate. + } + } + throw new Error(`Could not find built HTML for ${urlPath} (looked in ${candidates.join(', ')})`); +} + +async function loadFromUrl(base, urlPath) { + const url = new URL(urlPath, base).href; + const res = await fetch(url, { + headers: { + 'User-Agent': 'Mozilla/5.0 (compatible; warp-seo-audit/1.0)', + 'Accept': 'text/html', + }, + redirect: 'follow', + }); + if (!res.ok) { + throw new Error(`${url} → HTTP ${res.status}`); + } + return await res.text(); +} + +function format(value, width = 80) { + if (value == null) return '— missing —'; + const single = value.replace(/\s+/g, ' ').trim(); + return single.length > width ? `${single.slice(0, width - 1)}…` : single; +} + +async function fetchOne(args, urlPath) { + if (args.dist) { + return loadFromDist(path.resolve(args.dist), urlPath); + } + if (args.base) { + return loadFromUrl(args.base, urlPath); + } + throw new Error('Must pass --dist <dir> or --base <url>'); +} + +async function main() { + const args = parseArgs(process.argv.slice(2)); + if (args.help) { + console.log( + [ + 'SEO audit — checks for the meta tags GitBook emitted on every page', + 'so we don\'t regress when migrating to Astro/Starlight.', + '', + 'Usage:', + ' node scripts/seo-audit.mjs --dist ./dist [paths...]', + ' node scripts/seo-audit.mjs --base https://docs.warp.dev [paths...]', + ' node scripts/seo-audit.mjs --base <url> --compare <url> [paths...]', + '', + 'If no paths are passed, a default high-traffic set is audited.', + ].join('\n'), + ); + return; + } + + if (!args.dist && !args.base) { + console.error('Error: provide --dist <dir> (built site) or --base <url> (live site).'); + process.exit(2); + } + + const paths = args.paths.length ? args.paths : DEFAULT_PATHS; + let totalMissing = 0; + + for (const p of paths) { + console.log(`\n=== ${p} ===`); + let primary; + try { + primary = audit(await fetchOne(args, p)); + } catch (err) { + console.error(` ERROR: ${err.message}`); + totalMissing += REQUIRED_TAGS.length; + continue; + } + + let compare = null; + if (args.compare) { + try { + compare = audit(await loadFromUrl(args.compare, p)); + } catch (err) { + console.error(` compare ERROR: ${err.message}`); + } + } + + for (const { key, label } of REQUIRED_TAGS) { + const got = primary[key]; + const cmp = compare?.[key]; + const status = got == null ? '✗' : '✓'; + if (got == null) totalMissing += 1; + let line = ` ${status} ${label.padEnd(48)} ${format(got)}`; + if (compare) { + line += `\n compare: ${format(cmp)}`; + if (got !== cmp && got != null && cmp != null) { + line += '\n (values differ — review for parity)'; + } + } + console.log(line); + } + } + + if (totalMissing > 0) { + console.error(`\n${totalMissing} missing tag(s) across ${paths.length} page(s).`); + process.exit(1); + } + console.log(`\nAll required tags present across ${paths.length} page(s).`); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/scripts/sync-gitbook-changes.py b/scripts/sync-gitbook-changes.py new file mode 100755 index 0000000..3e72b43 --- /dev/null +++ b/scripts/sync-gitbook-changes.py @@ -0,0 +1,267 @@ +#!/usr/bin/env python3 +"""Incrementally sync new/modified gitbook files into the Starlight docs repo. + +Reuses the conversion logic in `migrate-all.py` (which itself imports +`convert-gitbook.py`) and limits the work to the files reported by +`git diff --name-status <baseline>..<head>` in the gitbook repo. + +Usage: + python scripts/sync-gitbook-changes.py /path/to/gitbook \\ + [--baseline bf06b82f] [--head main] [--dry-run] + +Behavior: +- Files added or modified under `docs/<space>/...` or `guides/...` are + converted via `migrate_all.convert_file_enhanced` and written into + `src/content/docs/...` using the same path mapping as the original migration. +- Files deleted in gitbook are deleted in docs. +- README.md/SUMMARY.md/.gitbook/* changes that aren't content are skipped. +- Existing docs files that were intentionally diverged from gitbook (e.g. + `agent-modality.mdx` keeping the legacy slug) are still overwritten when + their gitbook source changed; the caller is expected to do post-processing + for renames or splits (self-hosting/, migrate-to-warp/, terminal/settings/). + +This script never touches `vercel.json` or `src/sidebar.ts` — those are +edited separately so reviewers can see the navigation and redirect changes +clearly. +""" + +from __future__ import annotations + +import argparse +import shutil +import subprocess +import sys +from importlib.machinery import SourceFileLoader +from pathlib import Path +from typing import Iterable + +SCRIPT_DIR = Path(__file__).resolve().parent +DOCS_ROOT = SCRIPT_DIR.parent +STARLIGHT_DOCS = DOCS_ROOT / "src" / "content" / "docs" + +# Load the existing conversion machinery +migrate_all = SourceFileLoader( + "migrate_all", str(SCRIPT_DIR / "migrate-all.py") +).load_module() + + +SPACE_PREFIXES = ( + ("docs/warp/", "warp"), + ("docs/agent-platform/", "agent-platform"), + ("docs/reference/", "reference"), + ("docs/support-and-community/", "support-and-community"), + ("docs/enterprise/", "enterprise"), + ("docs/changelog/", "changelog"), + ("guides/", "guides"), +) + +# These paths are content but should not be auto-converted; they need manual +# handling (see plan). +SKIP_FILES = { + # SUMMARY.md drives sidebars; we map them to src/sidebar.ts manually. + "SUMMARY.md", + # .gitbook.yaml drives redirects; we port them to vercel.json manually. + ".gitbook.yaml", +} + +# JSX components that are docs-only design improvements (introduced after the +# original full migration, e.g. the FileTree migration in PR #50 and the +# DemoVideo component). When the docs file already uses one of these, the +# sync script will skip the file and report it instead of overwriting; the +# operator should hand-merge the gitbook diff in those cases. +DOCS_ONLY_JSX_GUARDS = ( + "<FileTree", + "<DemoVideo", +) + + +def gitbook_space_root(gitbook_root: Path, space: str) -> Path: + if space == "guides": + return gitbook_root / "guides" + return gitbook_root / "docs" / space + + +def classify(rel_path: str) -> tuple[str, str] | None: + """Return (space, rel_in_space) or None for non-content paths.""" + name = rel_path.rsplit("/", 1)[-1] + if name in SKIP_FILES: + return None + if "/.gitbook/" in rel_path or rel_path.startswith(".gitbook/"): + return None + if rel_path.startswith("docs/_book/"): + return None + if not rel_path.endswith(".md"): + return None + + for prefix, space in SPACE_PREFIXES: + if rel_path.startswith(prefix): + return space, rel_path[len(prefix):] + return None + + +def list_changes( + gitbook_root: Path, baseline: str, head: str +) -> list[tuple[str, str]]: + """Return [(status, path), ...] from git diff --name-status.""" + out = subprocess.check_output( + [ + "git", + "-C", + str(gitbook_root), + "--no-pager", + "diff", + "--name-status", + f"{baseline}..{head}", + ], + text=True, + ) + rows: list[tuple[str, str]] = [] + for line in out.splitlines(): + if not line.strip(): + continue + parts = line.split("\t") + if len(parts) < 2: + continue + status = parts[0][0] + # For renames, the new path is the last column. + path = parts[-1] + rows.append((status, path)) + return rows + + +def docs_dst_for(space: str, rel_in_space: str) -> Path: + dst_rel = migrate_all.map_gitbook_path(space, rel_in_space) + return STARLIGHT_DOCS / dst_rel + + +def has_docs_only_jsx(dst: Path) -> list[str]: + """Return the list of docs-only JSX guards present in `dst`, or [] if none.""" + if not dst.exists(): + return [] + text = dst.read_text(encoding="utf-8") + return [g for g in DOCS_ONLY_JSX_GUARDS if g in text] + + +def convert_one(gitbook_root: Path, space: str, rel_in_space: str, dry_run: bool) -> str: + src = gitbook_space_root(gitbook_root, space) / rel_in_space + dst = docs_dst_for(space, rel_in_space) + if not src.exists(): + return f" ⚠ source missing: {src}" + # Refuse to overwrite a docs file that contains docs-only JSX components. + # The operator must 3-way merge the gitbook diff manually (restore docs/ + # main, then re-apply just the gitbook content updates) so the design + # components are preserved. + guards = has_docs_only_jsx(dst) + if guards: + return ( + f" ⚠ SKIPPED (docs-only JSX present, hand-merge required): " + f"{space}/{rel_in_space} → {dst.relative_to(DOCS_ROOT)} " + f"[{','.join(guards)}]" + ) + if dry_run: + return f" [dry-run] {space}/{rel_in_space} → {dst.relative_to(DOCS_ROOT)}" + dst.parent.mkdir(parents=True, exist_ok=True) + result = migrate_all.convert_file_enhanced( + src, dst, space, gitbook_space_root(gitbook_root, space), DOCS_ROOT + ) + dst.write_text(result, encoding="utf-8") + return f" ✓ {space}/{rel_in_space} → {dst.relative_to(DOCS_ROOT)}" + + +def delete_one(space: str, rel_in_space: str, dry_run: bool) -> str: + dst = docs_dst_for(space, rel_in_space) + if not dst.exists(): + return f" ⊘ docs file already absent: {dst.relative_to(DOCS_ROOT)}" + if dry_run: + return f" [dry-run] delete {dst.relative_to(DOCS_ROOT)}" + dst.unlink() + # Clean up empty parent dirs + parent = dst.parent + while parent != STARLIGHT_DOCS and parent.exists() and not any(parent.iterdir()): + parent.rmdir() + parent = parent.parent + return f" ✗ deleted {dst.relative_to(DOCS_ROOT)}" + + +def copy_changed_assets( + gitbook_root: Path, changed: Iterable[tuple[str, str]], dry_run: bool +) -> int: + """Copy any asset images that changed (under docs/<space>/.gitbook/assets/).""" + copied = 0 + for status, path in changed: + if status == "D": + continue + if "/.gitbook/assets/" not in path: + continue + # Determine which space the asset belongs to + for prefix, space in SPACE_PREFIXES: + if path.startswith(prefix): + break + else: + continue + asset_dir = migrate_all.map_asset_space(space) + src = gitbook_root / path + if not src.exists(): + continue + dst = DOCS_ROOT / "src" / "assets" / asset_dir / migrate_all.sanitize_asset_filename(src.name) + if dry_run: + print(f" [dry-run] asset {src.relative_to(gitbook_root)} → {dst.relative_to(DOCS_ROOT)}") + continue + dst.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(src, dst) + copied += 1 + print(f" 📎 asset {src.relative_to(gitbook_root)} → {dst.relative_to(DOCS_ROOT)}") + return copied + + +def main() -> int: + ap = argparse.ArgumentParser(description=__doc__) + ap.add_argument("gitbook", type=Path, help="Path to the gitbook repo root") + ap.add_argument("--baseline", default="bf06b82f", help="Git ref representing the last sync") + ap.add_argument("--head", default="main", help="Git ref to sync to") + ap.add_argument("--dry-run", action="store_true", help="Plan only; don't write") + args = ap.parse_args() + + gitbook_root = args.gitbook.resolve() + if not (gitbook_root / "docs").is_dir(): + print(f"Error: {gitbook_root}/docs is not a directory") + return 1 + + rows = list_changes(gitbook_root, args.baseline, args.head) + print(f"Found {len(rows)} changed paths between {args.baseline}..{args.head}") + + converted = deleted = skipped = 0 + log: list[str] = [] + for status, path in rows: + cls = classify(path) + if cls is None: + skipped += 1 + continue + space, rel = cls + # Honor docs-specific skip set for orphaned/duplicate gitbook files. + if rel in migrate_all.SKIP_PATHS.get(space, set()): + log.append(f" ⊘ skipped (intentional drop): {space}/{rel}") + skipped += 1 + continue + if status == "D": + log.append(delete_one(space, rel, args.dry_run)) + deleted += 1 + else: + # A, M, or R (treated as add/modify of the new path) + log.append(convert_one(gitbook_root, space, rel, args.dry_run)) + converted += 1 + + print() + for line in log: + print(line) + print() + + asset_count = copy_changed_assets(gitbook_root, rows, args.dry_run) + + print() + print(f"Summary: {converted} converted, {deleted} deleted, {skipped} skipped (non-content), {asset_count} assets copied") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/assets/agent-platform/@-reference-plans.png b/src/assets/agent-platform/@-reference-plans.png new file mode 100644 index 0000000..bc2e9b1 Binary files /dev/null and b/src/assets/agent-platform/@-reference-plans.png differ diff --git a/src/assets/agent-platform/Add-diff-as-context.png b/src/assets/agent-platform/Add-diff-as-context.png new file mode 100644 index 0000000..c30d5ec Binary files /dev/null and b/src/assets/agent-platform/Add-diff-as-context.png differ diff --git a/src/assets/agent-platform/MCP_servers_agent_permissions.png b/src/assets/agent-platform/MCP_servers_agent_permissions.png new file mode 100644 index 0000000..344ffcc Binary files /dev/null and b/src/assets/agent-platform/MCP_servers_agent_permissions.png differ diff --git a/src/assets/agent-platform/admin-panel-enabled-github-orgs.png b/src/assets/agent-platform/admin-panel-enabled-github-orgs.png new file mode 100644 index 0000000..d5e2845 Binary files /dev/null and b/src/assets/agent-platform/admin-panel-enabled-github-orgs.png differ diff --git a/src/assets/agent-platform/agent-conversations-new-modality.png b/src/assets/agent-platform/agent-conversations-new-modality.png new file mode 100644 index 0000000..5e8cc92 Binary files /dev/null and b/src/assets/agent-platform/agent-conversations-new-modality.png differ diff --git a/src/assets/agent-platform/agent-modality-conversation-view.png b/src/assets/agent-platform/agent-modality-conversation-view.png new file mode 100644 index 0000000..6ef1506 Binary files /dev/null and b/src/assets/agent-platform/agent-modality-conversation-view.png differ diff --git a/src/assets/agent-platform/agent-permissions-with-full-terminal-use.png b/src/assets/agent-platform/agent-permissions-with-full-terminal-use.png new file mode 100644 index 0000000..bf381f2 Binary files /dev/null and b/src/assets/agent-platform/agent-permissions-with-full-terminal-use.png differ diff --git a/src/assets/agent-platform/agent-plans-synced.png b/src/assets/agent-platform/agent-plans-synced.png new file mode 100644 index 0000000..b6a3aa0 Binary files /dev/null and b/src/assets/agent-platform/agent-plans-synced.png differ diff --git a/src/assets/agent-platform/agent-plans-tasks.png b/src/assets/agent-platform/agent-plans-tasks.png new file mode 100644 index 0000000..770f738 Binary files /dev/null and b/src/assets/agent-platform/agent-plans-tasks.png differ diff --git a/src/assets/agent-platform/agent-plans-versioning.png b/src/assets/agent-platform/agent-plans-versioning.png new file mode 100644 index 0000000..cf42bf2 Binary files /dev/null and b/src/assets/agent-platform/agent-plans-versioning.png differ diff --git a/src/assets/agent-platform/agent-profiles-allow-and-denylists.png b/src/assets/agent-platform/agent-profiles-allow-and-denylists.png new file mode 100644 index 0000000..01a396a Binary files /dev/null and b/src/assets/agent-platform/agent-profiles-allow-and-denylists.png differ diff --git a/src/assets/agent-platform/agent-profiles-settings.png b/src/assets/agent-platform/agent-profiles-settings.png new file mode 100644 index 0000000..1560870 Binary files /dev/null and b/src/assets/agent-platform/agent-profiles-settings.png differ diff --git a/src/assets/agent-platform/agent-profiles.png b/src/assets/agent-platform/agent-profiles.png new file mode 100644 index 0000000..3268384 Binary files /dev/null and b/src/assets/agent-platform/agent-profiles.png differ diff --git a/src/assets/agent-platform/agent-session-sharing-command-palette.png b/src/assets/agent-platform/agent-session-sharing-command-palette.png new file mode 100644 index 0000000..8343825 Binary files /dev/null and b/src/assets/agent-platform/agent-session-sharing-command-palette.png differ diff --git a/src/assets/agent-platform/agent-session-sharing-right-click-menu.png b/src/assets/agent-platform/agent-session-sharing-right-click-menu.png new file mode 100644 index 0000000..f6498d5 Binary files /dev/null and b/src/assets/agent-platform/agent-session-sharing-right-click-menu.png differ diff --git a/src/assets/agent-platform/agent-tips.png b/src/assets/agent-platform/agent-tips.png new file mode 100644 index 0000000..10b0adc Binary files /dev/null and b/src/assets/agent-platform/agent-tips.png differ diff --git a/src/assets/agent-platform/allow-refine-takeover.png b/src/assets/agent-platform/allow-refine-takeover.png new file mode 100644 index 0000000..6ae5c11 Binary files /dev/null and b/src/assets/agent-platform/allow-refine-takeover.png differ diff --git a/src/assets/agent-platform/at-context-app.png b/src/assets/agent-platform/at-context-app.png new file mode 100644 index 0000000..6d78304 Binary files /dev/null and b/src/assets/agent-platform/at-context-app.png differ diff --git a/src/assets/agent-platform/at-context-styles.png b/src/assets/agent-platform/at-context-styles.png new file mode 100644 index 0000000..6fa227e Binary files /dev/null and b/src/assets/agent-platform/at-context-styles.png differ diff --git a/src/assets/agent-platform/at-context.png b/src/assets/agent-platform/at-context.png new file mode 100644 index 0000000..d7cba00 Binary files /dev/null and b/src/assets/agent-platform/at-context.png differ diff --git a/src/assets/agent-platform/auto-sync-plans-1.png b/src/assets/agent-platform/auto-sync-plans-1.png new file mode 100644 index 0000000..4309952 Binary files /dev/null and b/src/assets/agent-platform/auto-sync-plans-1.png differ diff --git a/src/assets/agent-platform/classic-input-follow-up.png b/src/assets/agent-platform/classic-input-follow-up.png new file mode 100644 index 0000000..10ca9fc Binary files /dev/null and b/src/assets/agent-platform/classic-input-follow-up.png differ diff --git a/src/assets/agent-platform/classic-input-new-convo.png b/src/assets/agent-platform/classic-input-new-convo.png new file mode 100644 index 0000000..4d44c07 Binary files /dev/null and b/src/assets/agent-platform/classic-input-new-convo.png differ diff --git a/src/assets/agent-platform/cli-agent-toolbelt.png b/src/assets/agent-platform/cli-agent-toolbelt.png new file mode 100644 index 0000000..a6357f5 Binary files /dev/null and b/src/assets/agent-platform/cli-agent-toolbelt.png differ diff --git a/src/assets/agent-platform/cloud-agents-infra.png b/src/assets/agent-platform/cloud-agents-infra.png new file mode 100644 index 0000000..b64a206 Binary files /dev/null and b/src/assets/agent-platform/cloud-agents-infra.png differ diff --git a/src/assets/agent-platform/codebase-context-main.png b/src/assets/agent-platform/codebase-context-main.png new file mode 100644 index 0000000..caec9a8 Binary files /dev/null and b/src/assets/agent-platform/codebase-context-main.png differ diff --git a/src/assets/agent-platform/codebase-context-statuses.png b/src/assets/agent-platform/codebase-context-statuses.png new file mode 100644 index 0000000..dba9d09 Binary files /dev/null and b/src/assets/agent-platform/codebase-context-statuses.png differ diff --git a/src/assets/agent-platform/completion-markers.png b/src/assets/agent-platform/completion-markers.png new file mode 100644 index 0000000..d265035 Binary files /dev/null and b/src/assets/agent-platform/completion-markers.png differ diff --git a/src/assets/agent-platform/context-derived-from-memory.png b/src/assets/agent-platform/context-derived-from-memory.png new file mode 100644 index 0000000..87a00de Binary files /dev/null and b/src/assets/agent-platform/context-derived-from-memory.png differ diff --git a/src/assets/agent-platform/context-references-memory.png b/src/assets/agent-platform/context-references-memory.png new file mode 100644 index 0000000..580cbe2 Binary files /dev/null and b/src/assets/agent-platform/context-references-memory.png differ diff --git a/src/assets/agent-platform/context-window-1.png b/src/assets/agent-platform/context-window-1.png new file mode 100644 index 0000000..87b334f Binary files /dev/null and b/src/assets/agent-platform/context-window-1.png differ diff --git a/src/assets/agent-platform/context-window-2-1.png b/src/assets/agent-platform/context-window-2-1.png new file mode 100644 index 0000000..e40fc2d Binary files /dev/null and b/src/assets/agent-platform/context-window-2-1.png differ diff --git a/src/assets/agent-platform/context-window-2.png b/src/assets/agent-platform/context-window-2.png new file mode 100644 index 0000000..94ab5eb Binary files /dev/null and b/src/assets/agent-platform/context-window-2.png differ diff --git a/src/assets/agent-platform/context-window-3.png b/src/assets/agent-platform/context-window-3.png new file mode 100644 index 0000000..f52b179 Binary files /dev/null and b/src/assets/agent-platform/context-window-3.png differ diff --git a/src/assets/agent-platform/conversation-fork-and-compact.png b/src/assets/agent-platform/conversation-fork-and-compact.png new file mode 100644 index 0000000..6b203ff Binary files /dev/null and b/src/assets/agent-platform/conversation-fork-and-compact.png differ diff --git a/src/assets/agent-platform/conversation-forking-chip.png b/src/assets/agent-platform/conversation-forking-chip.png new file mode 100644 index 0000000..4ad3561 Binary files /dev/null and b/src/assets/agent-platform/conversation-forking-chip.png differ diff --git a/src/assets/agent-platform/conversation-forking-footer.png b/src/assets/agent-platform/conversation-forking-footer.png new file mode 100644 index 0000000..4d05d9b Binary files /dev/null and b/src/assets/agent-platform/conversation-forking-footer.png differ diff --git a/src/assets/agent-platform/conversation-forking-open-conversations.png b/src/assets/agent-platform/conversation-forking-open-conversations.png new file mode 100644 index 0000000..78a0cc4 Binary files /dev/null and b/src/assets/agent-platform/conversation-forking-open-conversations.png differ diff --git a/src/assets/agent-platform/conversation-forking-palette.png b/src/assets/agent-platform/conversation-forking-palette.png new file mode 100644 index 0000000..7692396 Binary files /dev/null and b/src/assets/agent-platform/conversation-forking-palette.png differ diff --git a/src/assets/agent-platform/conversation-segmentation.png b/src/assets/agent-platform/conversation-segmentation.png new file mode 100644 index 0000000..1c939ae Binary files /dev/null and b/src/assets/agent-platform/conversation-segmentation.png differ diff --git a/src/assets/agent-platform/customer-dedicated-saas.png b/src/assets/agent-platform/customer-dedicated-saas.png new file mode 100644 index 0000000..64ead33 Binary files /dev/null and b/src/assets/agent-platform/customer-dedicated-saas.png differ diff --git a/src/assets/agent-platform/delete-warpy.png b/src/assets/agent-platform/delete-warpy.png new file mode 100644 index 0000000..d1cf0fe Binary files /dev/null and b/src/assets/agent-platform/delete-warpy.png differ diff --git a/src/assets/agent-platform/editting_diff.png b/src/assets/agent-platform/editting_diff.png new file mode 100644 index 0000000..3e295be Binary files /dev/null and b/src/assets/agent-platform/editting_diff.png differ diff --git a/src/assets/agent-platform/enable-cli-agent-notifications.png b/src/assets/agent-platform/enable-cli-agent-notifications.png new file mode 100644 index 0000000..7cc1559 Binary files /dev/null and b/src/assets/agent-platform/enable-cli-agent-notifications.png differ diff --git a/src/assets/agent-platform/export-notebooks.png b/src/assets/agent-platform/export-notebooks.png new file mode 100644 index 0000000..03cb4b5 Binary files /dev/null and b/src/assets/agent-platform/export-notebooks.png differ diff --git a/src/assets/agent-platform/follow-up-universal-input.png b/src/assets/agent-platform/follow-up-universal-input.png new file mode 100644 index 0000000..53193ed Binary files /dev/null and b/src/assets/agent-platform/follow-up-universal-input.png differ diff --git a/src/assets/agent-platform/full-terminal-use-build.png b/src/assets/agent-platform/full-terminal-use-build.png new file mode 100644 index 0000000..27e8e6f Binary files /dev/null and b/src/assets/agent-platform/full-terminal-use-build.png differ diff --git a/src/assets/agent-platform/full-terminal-use-dev-monitor.png b/src/assets/agent-platform/full-terminal-use-dev-monitor.png new file mode 100644 index 0000000..58d9e6f Binary files /dev/null and b/src/assets/agent-platform/full-terminal-use-dev-monitor.png differ diff --git a/src/assets/agent-platform/full-terminal-use-handoff.png b/src/assets/agent-platform/full-terminal-use-handoff.png new file mode 100644 index 0000000..77a9086 Binary files /dev/null and b/src/assets/agent-platform/full-terminal-use-handoff.png differ diff --git a/src/assets/agent-platform/full-terminal-use-options-2.png b/src/assets/agent-platform/full-terminal-use-options-2.png new file mode 100644 index 0000000..947c497 Binary files /dev/null and b/src/assets/agent-platform/full-terminal-use-options-2.png differ diff --git a/src/assets/agent-platform/full-terminal-use-tag-hint.png b/src/assets/agent-platform/full-terminal-use-tag-hint.png new file mode 100644 index 0000000..340aea2 Binary files /dev/null and b/src/assets/agent-platform/full-terminal-use-tag-hint.png differ diff --git a/src/assets/agent-platform/full-terminal-use-takeover.png b/src/assets/agent-platform/full-terminal-use-takeover.png new file mode 100644 index 0000000..efa5d3d Binary files /dev/null and b/src/assets/agent-platform/full-terminal-use-takeover.png differ diff --git a/src/assets/agent-platform/generate-psql.png b/src/assets/agent-platform/generate-psql.png new file mode 100644 index 0000000..8715662 Binary files /dev/null and b/src/assets/agent-platform/generate-psql.png differ diff --git a/src/assets/agent-platform/generate-vim.png b/src/assets/agent-platform/generate-vim.png new file mode 100644 index 0000000..338c694 Binary files /dev/null and b/src/assets/agent-platform/generate-vim.png differ diff --git a/src/assets/agent-platform/generated_blocklist_diff.png b/src/assets/agent-platform/generated_blocklist_diff.png new file mode 100644 index 0000000..b46a55c Binary files /dev/null and b/src/assets/agent-platform/generated_blocklist_diff.png differ diff --git a/src/assets/agent-platform/git-diff-full-view.png b/src/assets/agent-platform/git-diff-full-view.png new file mode 100644 index 0000000..47423aa Binary files /dev/null and b/src/assets/agent-platform/git-diff-full-view.png differ diff --git a/src/assets/agent-platform/image-as-context-classic.png b/src/assets/agent-platform/image-as-context-classic.png new file mode 100644 index 0000000..9df3481 Binary files /dev/null and b/src/assets/agent-platform/image-as-context-classic.png differ diff --git a/src/assets/agent-platform/image-as-context-universal.png b/src/assets/agent-platform/image-as-context-universal.png new file mode 100644 index 0000000..80b86c4 Binary files /dev/null and b/src/assets/agent-platform/image-as-context-universal.png differ diff --git a/src/assets/agent-platform/in-progress-tasklist.png b/src/assets/agent-platform/in-progress-tasklist.png new file mode 100644 index 0000000..8fc56bb Binary files /dev/null and b/src/assets/agent-platform/in-progress-tasklist.png differ diff --git a/src/assets/agent-platform/init-setup-flow-1.png b/src/assets/agent-platform/init-setup-flow-1.png new file mode 100644 index 0000000..6f17d3c Binary files /dev/null and b/src/assets/agent-platform/init-setup-flow-1.png differ diff --git a/src/assets/agent-platform/init-setup-flow-2.png b/src/assets/agent-platform/init-setup-flow-2.png new file mode 100644 index 0000000..a32d318 Binary files /dev/null and b/src/assets/agent-platform/init-setup-flow-2.png differ diff --git a/src/assets/agent-platform/interactive-code-review-adding-comment.png b/src/assets/agent-platform/interactive-code-review-adding-comment.png new file mode 100644 index 0000000..6d67e7a Binary files /dev/null and b/src/assets/agent-platform/interactive-code-review-adding-comment.png differ diff --git a/src/assets/agent-platform/interactive-code-review-batch-comments.png b/src/assets/agent-platform/interactive-code-review-batch-comments.png new file mode 100644 index 0000000..fbdc702 Binary files /dev/null and b/src/assets/agent-platform/interactive-code-review-batch-comments.png differ diff --git a/src/assets/agent-platform/linear-warp-on-web.png b/src/assets/agent-platform/linear-warp-on-web.png new file mode 100644 index 0000000..0486003 Binary files /dev/null and b/src/assets/agent-platform/linear-warp-on-web.png differ diff --git a/src/assets/agent-platform/management-view-scannable-list.png b/src/assets/agent-platform/management-view-scannable-list.png new file mode 100644 index 0000000..0b4cbbf Binary files /dev/null and b/src/assets/agent-platform/management-view-scannable-list.png differ diff --git a/src/assets/agent-platform/manually-trigger-plan.png b/src/assets/agent-platform/manually-trigger-plan.png new file mode 100644 index 0000000..6a2f4dc Binary files /dev/null and b/src/assets/agent-platform/manually-trigger-plan.png differ diff --git a/src/assets/agent-platform/mcp-servers-add-cli.png b/src/assets/agent-platform/mcp-servers-add-cli.png new file mode 100644 index 0000000..bba6b7d Binary files /dev/null and b/src/assets/agent-platform/mcp-servers-add-cli.png differ diff --git a/src/assets/agent-platform/mcp-servers-add-sse.png b/src/assets/agent-platform/mcp-servers-add-sse.png new file mode 100644 index 0000000..99cfe94 Binary files /dev/null and b/src/assets/agent-platform/mcp-servers-add-sse.png differ diff --git a/src/assets/agent-platform/mcp-servers-list.png b/src/assets/agent-platform/mcp-servers-list.png new file mode 100644 index 0000000..283d902 Binary files /dev/null and b/src/assets/agent-platform/mcp-servers-list.png differ diff --git a/src/assets/agent-platform/mcp-servers-share.png b/src/assets/agent-platform/mcp-servers-share.png new file mode 100644 index 0000000..ef9c07a Binary files /dev/null and b/src/assets/agent-platform/mcp-servers-share.png differ diff --git a/src/assets/agent-platform/model-selector-dropdown.png b/src/assets/agent-platform/model-selector-dropdown.png new file mode 100644 index 0000000..ac1ed11 Binary files /dev/null and b/src/assets/agent-platform/model-selector-dropdown.png differ diff --git a/src/assets/agent-platform/most-flexible-platform-for-building-with-agents.png b/src/assets/agent-platform/most-flexible-platform-for-building-with-agents.png new file mode 100644 index 0000000..794a0e0 Binary files /dev/null and b/src/assets/agent-platform/most-flexible-platform-for-building-with-agents.png differ diff --git a/src/assets/agent-platform/next-command.png b/src/assets/agent-platform/next-command.png new file mode 100644 index 0000000..289af9c Binary files /dev/null and b/src/assets/agent-platform/next-command.png differ diff --git a/src/assets/agent-platform/notification-mailbox.png b/src/assets/agent-platform/notification-mailbox.png new file mode 100644 index 0000000..ff9410e Binary files /dev/null and b/src/assets/agent-platform/notification-mailbox.png differ diff --git a/src/assets/agent-platform/open-ai-commands.png b/src/assets/agent-platform/open-ai-commands.png new file mode 100644 index 0000000..7b0133b Binary files /dev/null and b/src/assets/agent-platform/open-ai-commands.png differ diff --git a/src/assets/agent-platform/oz-diagram.png b/src/assets/agent-platform/oz-diagram.png new file mode 100644 index 0000000..f179326 Binary files /dev/null and b/src/assets/agent-platform/oz-diagram.png differ diff --git a/src/assets/agent-platform/oz-github-app-installation.png b/src/assets/agent-platform/oz-github-app-installation.png new file mode 100644 index 0000000..b10354e Binary files /dev/null and b/src/assets/agent-platform/oz-github-app-installation.png differ diff --git a/src/assets/agent-platform/oz-use-cases.png b/src/assets/agent-platform/oz-use-cases.png new file mode 100644 index 0000000..b30fd26 Binary files /dev/null and b/src/assets/agent-platform/oz-use-cases.png differ diff --git a/src/assets/agent-platform/oz-web-app-agents.png b/src/assets/agent-platform/oz-web-app-agents.png new file mode 100644 index 0000000..98ef2bd Binary files /dev/null and b/src/assets/agent-platform/oz-web-app-agents.png differ diff --git a/src/assets/agent-platform/oz-web-app-environments.png b/src/assets/agent-platform/oz-web-app-environments.png new file mode 100644 index 0000000..0d98531 Binary files /dev/null and b/src/assets/agent-platform/oz-web-app-environments.png differ diff --git a/src/assets/agent-platform/oz-web-app-integrations.png b/src/assets/agent-platform/oz-web-app-integrations.png new file mode 100644 index 0000000..3516593 Binary files /dev/null and b/src/assets/agent-platform/oz-web-app-integrations.png differ diff --git a/src/assets/agent-platform/oz-web-app-new-agent.png b/src/assets/agent-platform/oz-web-app-new-agent.png new file mode 100644 index 0000000..1adef01 Binary files /dev/null and b/src/assets/agent-platform/oz-web-app-new-agent.png differ diff --git a/src/assets/agent-platform/oz-web-app-new-environment.png b/src/assets/agent-platform/oz-web-app-new-environment.png new file mode 100644 index 0000000..245f257 Binary files /dev/null and b/src/assets/agent-platform/oz-web-app-new-environment.png differ diff --git a/src/assets/agent-platform/oz-web-app-runs-view.png b/src/assets/agent-platform/oz-web-app-runs-view.png new file mode 100644 index 0000000..f579408 Binary files /dev/null and b/src/assets/agent-platform/oz-web-app-runs-view.png differ diff --git a/src/assets/agent-platform/oz-web-app-schedules.png b/src/assets/agent-platform/oz-web-app-schedules.png new file mode 100644 index 0000000..59bff9b Binary files /dev/null and b/src/assets/agent-platform/oz-web-app-schedules.png differ diff --git a/src/assets/agent-platform/plan-slash-command.png b/src/assets/agent-platform/plan-slash-command.png new file mode 100644 index 0000000..2dac8a2 Binary files /dev/null and b/src/assets/agent-platform/plan-slash-command.png differ diff --git a/src/assets/agent-platform/planning-main-view.png b/src/assets/agent-platform/planning-main-view.png new file mode 100644 index 0000000..2b9f06a Binary files /dev/null and b/src/assets/agent-platform/planning-main-view.png differ diff --git a/src/assets/agent-platform/plans-in-warp-drive-side-panel.png b/src/assets/agent-platform/plans-in-warp-drive-side-panel.png new file mode 100644 index 0000000..8d1a407 Binary files /dev/null and b/src/assets/agent-platform/plans-in-warp-drive-side-panel.png differ diff --git a/src/assets/agent-platform/project-scoped-rules-pane.png b/src/assets/agent-platform/project-scoped-rules-pane.png new file mode 100644 index 0000000..e998471 Binary files /dev/null and b/src/assets/agent-platform/project-scoped-rules-pane.png differ diff --git a/src/assets/agent-platform/prompt-suggestions-example-1.png b/src/assets/agent-platform/prompt-suggestions-example-1.png new file mode 100644 index 0000000..9068c40 Binary files /dev/null and b/src/assets/agent-platform/prompt-suggestions-example-1.png differ diff --git a/src/assets/agent-platform/prompt-suggestions-setting-1.png b/src/assets/agent-platform/prompt-suggestions-setting-1.png new file mode 100644 index 0000000..010f0d6 Binary files /dev/null and b/src/assets/agent-platform/prompt-suggestions-setting-1.png differ diff --git a/src/assets/agent-platform/remote-control.png b/src/assets/agent-platform/remote-control.png new file mode 100644 index 0000000..97e2300 Binary files /dev/null and b/src/assets/agent-platform/remote-control.png differ diff --git a/src/assets/agent-platform/remove-slack-app.png b/src/assets/agent-platform/remove-slack-app.png new file mode 100644 index 0000000..2241f1e Binary files /dev/null and b/src/assets/agent-platform/remove-slack-app.png differ diff --git a/src/assets/agent-platform/remove_all_untracked_files.png b/src/assets/agent-platform/remove_all_untracked_files.png new file mode 100644 index 0000000..974d0c1 Binary files /dev/null and b/src/assets/agent-platform/remove_all_untracked_files.png differ diff --git a/src/assets/agent-platform/rich-input-button.png b/src/assets/agent-platform/rich-input-button.png new file mode 100644 index 0000000..263925c Binary files /dev/null and b/src/assets/agent-platform/rich-input-button.png differ diff --git a/src/assets/agent-platform/rich-input-prompt.png b/src/assets/agent-platform/rich-input-prompt.png new file mode 100644 index 0000000..93fa9a9 Binary files /dev/null and b/src/assets/agent-platform/rich-input-prompt.png differ diff --git a/src/assets/agent-platform/rich-input-settings.png b/src/assets/agent-platform/rich-input-settings.png new file mode 100644 index 0000000..5bbe88c Binary files /dev/null and b/src/assets/agent-platform/rich-input-settings.png differ diff --git a/src/assets/agent-platform/run-until-completion.png b/src/assets/agent-platform/run-until-completion.png new file mode 100644 index 0000000..d0711cc Binary files /dev/null and b/src/assets/agent-platform/run-until-completion.png differ diff --git a/src/assets/agent-platform/selection-as-context.png b/src/assets/agent-platform/selection-as-context.png new file mode 100644 index 0000000..a89c369 Binary files /dev/null and b/src/assets/agent-platform/selection-as-context.png differ diff --git a/src/assets/agent-platform/send-to-agent.png b/src/assets/agent-platform/send-to-agent.png new file mode 100644 index 0000000..538ed0d Binary files /dev/null and b/src/assets/agent-platform/send-to-agent.png differ diff --git a/src/assets/agent-platform/slash-commands-agent-modality.png b/src/assets/agent-platform/slash-commands-agent-modality.png new file mode 100644 index 0000000..7baed27 Binary files /dev/null and b/src/assets/agent-platform/slash-commands-agent-modality.png differ diff --git a/src/assets/agent-platform/slash-commands-menu.png b/src/assets/agent-platform/slash-commands-menu.png new file mode 100644 index 0000000..d74394b Binary files /dev/null and b/src/assets/agent-platform/slash-commands-menu.png differ diff --git a/src/assets/agent-platform/slash-commands-prompts.png b/src/assets/agent-platform/slash-commands-prompts.png new file mode 100644 index 0000000..15807b8 Binary files /dev/null and b/src/assets/agent-platform/slash-commands-prompts.png differ diff --git a/src/assets/agent-platform/slash-commands-terminal-modality.png b/src/assets/agent-platform/slash-commands-terminal-modality.png new file mode 100644 index 0000000..1eba593 Binary files /dev/null and b/src/assets/agent-platform/slash-commands-terminal-modality.png differ diff --git a/src/assets/agent-platform/suggested-code-diffs-generating-fix.png b/src/assets/agent-platform/suggested-code-diffs-generating-fix.png new file mode 100644 index 0000000..0dabe7c Binary files /dev/null and b/src/assets/agent-platform/suggested-code-diffs-generating-fix.png differ diff --git a/src/assets/agent-platform/suggested-code-diffs.png b/src/assets/agent-platform/suggested-code-diffs.png new file mode 100644 index 0000000..a659d3c Binary files /dev/null and b/src/assets/agent-platform/suggested-code-diffs.png differ diff --git a/src/assets/agent-platform/tasklist-popup.png b/src/assets/agent-platform/tasklist-popup.png new file mode 100644 index 0000000..9180348 Binary files /dev/null and b/src/assets/agent-platform/tasklist-popup.png differ diff --git a/src/assets/agent-platform/tasklist-small.png b/src/assets/agent-platform/tasklist-small.png new file mode 100644 index 0000000..6846a8f Binary files /dev/null and b/src/assets/agent-platform/tasklist-small.png differ diff --git a/src/assets/agent-platform/terminal-modality.png b/src/assets/agent-platform/terminal-modality.png new file mode 100644 index 0000000..7727585 Binary files /dev/null and b/src/assets/agent-platform/terminal-modality.png differ diff --git a/src/assets/agent-platform/toast-notification.png b/src/assets/agent-platform/toast-notification.png new file mode 100644 index 0000000..e6f1e1c Binary files /dev/null and b/src/assets/agent-platform/toast-notification.png differ diff --git a/src/assets/agent-platform/universal-input-new-convo.png b/src/assets/agent-platform/universal-input-new-convo.png new file mode 100644 index 0000000..c6ce01b Binary files /dev/null and b/src/assets/agent-platform/universal-input-new-convo.png differ diff --git a/src/assets/agent-platform/update-agent-mid-plan.png b/src/assets/agent-platform/update-agent-mid-plan.png new file mode 100644 index 0000000..ad09cd9 Binary files /dev/null and b/src/assets/agent-platform/update-agent-mid-plan.png differ diff --git a/src/assets/agent-platform/url-as-context.png b/src/assets/agent-platform/url-as-context.png new file mode 100644 index 0000000..176c44d Binary files /dev/null and b/src/assets/agent-platform/url-as-context.png differ diff --git a/src/assets/agent-platform/voice-in-find.png b/src/assets/agent-platform/voice-in-find.png new file mode 100644 index 0000000..f221503 Binary files /dev/null and b/src/assets/agent-platform/voice-in-find.png differ diff --git a/src/assets/agent-platform/voice-settings.png b/src/assets/agent-platform/voice-settings.png new file mode 100644 index 0000000..8ec7b05 Binary files /dev/null and b/src/assets/agent-platform/voice-settings.png differ diff --git a/src/assets/agent-platform/web-search-results.png b/src/assets/agent-platform/web-search-results.png new file mode 100644 index 0000000..3233fd8 Binary files /dev/null and b/src/assets/agent-platform/web-search-results.png differ diff --git a/src/assets/agent-platform/web-search-settings.png b/src/assets/agent-platform/web-search-settings.png new file mode 100644 index 0000000..e895e9f Binary files /dev/null and b/src/assets/agent-platform/web-search-settings.png differ diff --git a/src/assets/guides/Screenshot-2025-10-07-at-10.44.14-AM.png b/src/assets/guides/Screenshot-2025-10-07-at-10.44.14-AM.png new file mode 100644 index 0000000..dd853bd Binary files /dev/null and b/src/assets/guides/Screenshot-2025-10-07-at-10.44.14-AM.png differ diff --git a/src/assets/guides/code-review-button.png b/src/assets/guides/code-review-button.png new file mode 100644 index 0000000..9872bea Binary files /dev/null and b/src/assets/guides/code-review-button.png differ diff --git a/src/assets/guides/code-review-file-sidebar.png b/src/assets/guides/code-review-file-sidebar.png new file mode 100644 index 0000000..0b26557 Binary files /dev/null and b/src/assets/guides/code-review-file-sidebar.png differ diff --git a/src/assets/guides/code-review-inline-comment.png b/src/assets/guides/code-review-inline-comment.png new file mode 100644 index 0000000..f6e5635 Binary files /dev/null and b/src/assets/guides/code-review-inline-comment.png differ diff --git a/src/assets/guides/code-review-panel-with-diffs.png b/src/assets/guides/code-review-panel-with-diffs.png new file mode 100644 index 0000000..04963f4 Binary files /dev/null and b/src/assets/guides/code-review-panel-with-diffs.png differ diff --git a/src/assets/guides/image-as-context.png b/src/assets/guides/image-as-context.png new file mode 100644 index 0000000..c1f62b1 Binary files /dev/null and b/src/assets/guides/image-as-context.png differ diff --git a/src/assets/guides/tab-notification-indicator.png b/src/assets/guides/tab-notification-indicator.png new file mode 100644 index 0000000..44767c4 Binary files /dev/null and b/src/assets/guides/tab-notification-indicator.png differ diff --git a/src/assets/guides/voice-input-microphone.png b/src/assets/guides/voice-input-microphone.png new file mode 100644 index 0000000..a1b430b Binary files /dev/null and b/src/assets/guides/voice-input-microphone.png differ diff --git a/src/assets/reference/api-key-management.png b/src/assets/reference/api-key-management.png new file mode 100644 index 0000000..1f1422a Binary files /dev/null and b/src/assets/reference/api-key-management.png differ diff --git a/src/assets/reference/mcp-server-id.png b/src/assets/reference/mcp-server-id.png new file mode 100644 index 0000000..98e9259 Binary files /dev/null and b/src/assets/reference/mcp-server-id.png differ diff --git a/src/assets/support-and-community/Pricing-Blog-BYOK.png b/src/assets/support-and-community/Pricing-Blog-BYOK.png new file mode 100644 index 0000000..c28ac66 Binary files /dev/null and b/src/assets/support-and-community/Pricing-Blog-BYOK.png differ diff --git a/src/assets/support-and-community/activity-monitor-sample-process.png b/src/assets/support-and-community/activity-monitor-sample-process.png new file mode 100644 index 0000000..f03d99b Binary files /dev/null and b/src/assets/support-and-community/activity-monitor-sample-process.png differ diff --git a/src/assets/support-and-community/auth-token-flow.png b/src/assets/support-and-community/auth-token-flow.png new file mode 100644 index 0000000..274f689 Binary files /dev/null and b/src/assets/support-and-community/auth-token-flow.png differ diff --git a/src/assets/support-and-community/byok-keys.png b/src/assets/support-and-community/byok-keys.png new file mode 100644 index 0000000..7120565 Binary files /dev/null and b/src/assets/support-and-community/byok-keys.png differ diff --git a/src/assets/support-and-community/fallback.png b/src/assets/support-and-community/fallback.png new file mode 100644 index 0000000..39201d8 Binary files /dev/null and b/src/assets/support-and-community/fallback.png differ diff --git a/src/assets/support-and-community/inline-credit-usage-footer.png b/src/assets/support-and-community/inline-credit-usage-footer.png new file mode 100644 index 0000000..380fc3f Binary files /dev/null and b/src/assets/support-and-community/inline-credit-usage-footer.png differ diff --git a/src/assets/support-and-community/mac-ssh-permission.png b/src/assets/support-and-community/mac-ssh-permission.png new file mode 100644 index 0000000..6886ea3 Binary files /dev/null and b/src/assets/support-and-community/mac-ssh-permission.png differ diff --git a/src/assets/support-and-community/overages-settings.png b/src/assets/support-and-community/overages-settings.png new file mode 100644 index 0000000..20297bb Binary files /dev/null and b/src/assets/support-and-community/overages-settings.png differ diff --git a/src/assets/support-and-community/permission-error-macos.png b/src/assets/support-and-community/permission-error-macos.png new file mode 100644 index 0000000..370abd6 Binary files /dev/null and b/src/assets/support-and-community/permission-error-macos.png differ diff --git a/src/assets/support-and-community/privacy-settings-after-signup-1.png b/src/assets/support-and-community/privacy-settings-after-signup-1.png new file mode 100644 index 0000000..116d317 Binary files /dev/null and b/src/assets/support-and-community/privacy-settings-after-signup-1.png differ diff --git a/src/assets/support-and-community/reload-credits.png b/src/assets/support-and-community/reload-credits.png new file mode 100644 index 0000000..7235dd1 Binary files /dev/null and b/src/assets/support-and-community/reload-credits.png differ diff --git a/src/assets/support-and-community/send-feedback-debugging-information.png b/src/assets/support-and-community/send-feedback-debugging-information.png new file mode 100644 index 0000000..e7404c6 Binary files /dev/null and b/src/assets/support-and-community/send-feedback-debugging-information.png differ diff --git a/src/assets/support-and-community/update-available-bar.png b/src/assets/support-and-community/update-available-bar.png new file mode 100644 index 0000000..5b32279 Binary files /dev/null and b/src/assets/support-and-community/update-available-bar.png differ diff --git a/src/assets/support-and-community/update-available.png b/src/assets/support-and-community/update-available.png new file mode 100644 index 0000000..976978f Binary files /dev/null and b/src/assets/support-and-community/update-available.png differ diff --git a/src/assets/terminal/Blocklist-with-review-changes.png b/src/assets/terminal/Blocklist-with-review-changes.png new file mode 100644 index 0000000..62fa47f Binary files /dev/null and b/src/assets/terminal/Blocklist-with-review-changes.png differ diff --git a/src/assets/terminal/Edit_Workflow.png b/src/assets/terminal/Edit_Workflow.png new file mode 100644 index 0000000..8e33c4c Binary files /dev/null and b/src/assets/terminal/Edit_Workflow.png differ diff --git a/src/assets/terminal/Open_Warp_Drive.png b/src/assets/terminal/Open_Warp_Drive.png new file mode 100644 index 0000000..0288f90 Binary files /dev/null and b/src/assets/terminal/Open_Warp_Drive.png differ diff --git a/src/assets/terminal/Warp_Drive_Zero_State.png b/src/assets/terminal/Warp_Drive_Zero_State.png new file mode 100644 index 0000000..d0cb979 Binary files /dev/null and b/src/assets/terminal/Warp_Drive_Zero_State.png differ diff --git a/src/assets/terminal/Warp_Drive_with_Team.png b/src/assets/terminal/Warp_Drive_with_Team.png new file mode 100644 index 0000000..062dd65 Binary files /dev/null and b/src/assets/terminal/Warp_Drive_with_Team.png differ diff --git a/src/assets/terminal/active-directory-chip.png b/src/assets/terminal/active-directory-chip.png new file mode 100644 index 0000000..fbafa08 Binary files /dev/null and b/src/assets/terminal/active-directory-chip.png differ diff --git a/src/assets/terminal/adeberry.png b/src/assets/terminal/adeberry.png new file mode 100644 index 0000000..5c5a5a4 Binary files /dev/null and b/src/assets/terminal/adeberry.png differ diff --git a/src/assets/terminal/admin-panel-overview.png b/src/assets/terminal/admin-panel-overview.png new file mode 100644 index 0000000..9a756ef Binary files /dev/null and b/src/assets/terminal/admin-panel-overview.png differ diff --git a/src/assets/terminal/agent-mode-locked-universal-input.png b/src/assets/terminal/agent-mode-locked-universal-input.png new file mode 100644 index 0000000..44313f3 Binary files /dev/null and b/src/assets/terminal/agent-mode-locked-universal-input.png differ diff --git a/src/assets/terminal/agent-mode-suggestion-1.png b/src/assets/terminal/agent-mode-suggestion-1.png new file mode 100644 index 0000000..36ee84d Binary files /dev/null and b/src/assets/terminal/agent-mode-suggestion-1.png differ diff --git a/src/assets/terminal/agent-status-badges.png b/src/assets/terminal/agent-status-badges.png new file mode 100644 index 0000000..6fb9108 Binary files /dev/null and b/src/assets/terminal/agent-status-badges.png differ diff --git a/src/assets/terminal/ai_control_panel_buttons_larger_view.png b/src/assets/terminal/ai_control_panel_buttons_larger_view.png new file mode 100644 index 0000000..9026ae0 Binary files /dev/null and b/src/assets/terminal/ai_control_panel_buttons_larger_view.png differ diff --git a/src/assets/terminal/annotated_blocks-1.png b/src/assets/terminal/annotated_blocks-1.png new file mode 100644 index 0000000..73638f2 Binary files /dev/null and b/src/assets/terminal/annotated_blocks-1.png differ diff --git a/src/assets/terminal/arbitrary-branch-diff.png b/src/assets/terminal/arbitrary-branch-diff.png new file mode 100644 index 0000000..c0aacdd Binary files /dev/null and b/src/assets/terminal/arbitrary-branch-diff.png differ diff --git a/src/assets/terminal/attach-diff-hunk-as-context.png b/src/assets/terminal/attach-diff-hunk-as-context.png new file mode 100644 index 0000000..d7bca69 Binary files /dev/null and b/src/assets/terminal/attach-diff-hunk-as-context.png differ diff --git a/src/assets/terminal/aurora-icon.png b/src/assets/terminal/aurora-icon.png new file mode 100644 index 0000000..ae67114 Binary files /dev/null and b/src/assets/terminal/aurora-icon.png differ diff --git a/src/assets/terminal/auto-detection-agent-mode-1.png b/src/assets/terminal/auto-detection-agent-mode-1.png new file mode 100644 index 0000000..3004058 Binary files /dev/null and b/src/assets/terminal/auto-detection-agent-mode-1.png differ diff --git a/src/assets/terminal/auto-detection-off-agent-mode.png b/src/assets/terminal/auto-detection-off-agent-mode.png new file mode 100644 index 0000000..18af28c Binary files /dev/null and b/src/assets/terminal/auto-detection-off-agent-mode.png differ diff --git a/src/assets/terminal/auto-detection-off-terminal-mode.png b/src/assets/terminal/auto-detection-off-terminal-mode.png new file mode 100644 index 0000000..3347460 Binary files /dev/null and b/src/assets/terminal/auto-detection-off-terminal-mode.png differ diff --git a/src/assets/terminal/auto-detection-terminal-mode.png b/src/assets/terminal/auto-detection-terminal-mode.png new file mode 100644 index 0000000..4a1d11d Binary files /dev/null and b/src/assets/terminal/auto-detection-terminal-mode.png differ diff --git a/src/assets/terminal/banner_for_auto-detection_first_experience.png b/src/assets/terminal/banner_for_auto-detection_first_experience.png new file mode 100644 index 0000000..33884cb Binary files /dev/null and b/src/assets/terminal/banner_for_auto-detection_first_experience.png differ diff --git a/src/assets/terminal/classic1-icon.png b/src/assets/terminal/classic1-icon.png new file mode 100644 index 0000000..8a3c52e Binary files /dev/null and b/src/assets/terminal/classic1-icon.png differ diff --git a/src/assets/terminal/classic2-icon.png b/src/assets/terminal/classic2-icon.png new file mode 100644 index 0000000..6a59c1f Binary files /dev/null and b/src/assets/terminal/classic2-icon.png differ diff --git a/src/assets/terminal/classic3-icon.png b/src/assets/terminal/classic3-icon.png new file mode 100644 index 0000000..555ebd0 Binary files /dev/null and b/src/assets/terminal/classic3-icon.png differ diff --git a/src/assets/terminal/code-review-header.png b/src/assets/terminal/code-review-header.png new file mode 100644 index 0000000..07c81ea Binary files /dev/null and b/src/assets/terminal/code-review-header.png differ diff --git a/src/assets/terminal/code-review-panel-update.png b/src/assets/terminal/code-review-panel-update.png new file mode 100644 index 0000000..380b08f Binary files /dev/null and b/src/assets/terminal/code-review-panel-update.png differ diff --git a/src/assets/terminal/code_mode.png b/src/assets/terminal/code_mode.png new file mode 100644 index 0000000..a4cf0a1 Binary files /dev/null and b/src/assets/terminal/code_mode.png differ diff --git a/src/assets/terminal/comets-icon.png b/src/assets/terminal/comets-icon.png new file mode 100644 index 0000000..0403858 Binary files /dev/null and b/src/assets/terminal/comets-icon.png differ diff --git a/src/assets/terminal/command-history-rich.png b/src/assets/terminal/command-history-rich.png new file mode 100644 index 0000000..abf97bc Binary files /dev/null and b/src/assets/terminal/command-history-rich.png differ diff --git a/src/assets/terminal/command-palette-panel.png b/src/assets/terminal/command-palette-panel.png new file mode 100644 index 0000000..4c11592 Binary files /dev/null and b/src/assets/terminal/command-palette-panel.png differ diff --git a/src/assets/terminal/command-search-panel.png b/src/assets/terminal/command-search-panel.png new file mode 100644 index 0000000..0416002 Binary files /dev/null and b/src/assets/terminal/command-search-panel.png differ diff --git a/src/assets/terminal/conversation-management-chip-universal-input.png b/src/assets/terminal/conversation-management-chip-universal-input.png new file mode 100644 index 0000000..e6aebd7 Binary files /dev/null and b/src/assets/terminal/conversation-management-chip-universal-input.png differ diff --git a/src/assets/terminal/custom-dock-icon-dropdown.png b/src/assets/terminal/custom-dock-icon-dropdown.png new file mode 100644 index 0000000..e6181d5 Binary files /dev/null and b/src/assets/terminal/custom-dock-icon-dropdown.png differ diff --git a/src/assets/terminal/cyber-wave.png b/src/assets/terminal/cyber-wave.png new file mode 100644 index 0000000..2016bed Binary files /dev/null and b/src/assets/terminal/cyber-wave.png differ diff --git a/src/assets/terminal/dark-city.png b/src/assets/terminal/dark-city.png new file mode 100644 index 0000000..17befdf Binary files /dev/null and b/src/assets/terminal/dark-city.png differ diff --git a/src/assets/terminal/default-icon.png b/src/assets/terminal/default-icon.png new file mode 100644 index 0000000..5cd5e81 Binary files /dev/null and b/src/assets/terminal/default-icon.png differ diff --git a/src/assets/terminal/diff-dropdown-to-change-base-from-the-code-review-pane.png b/src/assets/terminal/diff-dropdown-to-change-base-from-the-code-review-pane.png new file mode 100644 index 0000000..067d344 Binary files /dev/null and b/src/assets/terminal/diff-dropdown-to-change-base-from-the-code-review-pane.png differ diff --git a/src/assets/terminal/discard-all-changes.png b/src/assets/terminal/discard-all-changes.png new file mode 100644 index 0000000..ee48079 Binary files /dev/null and b/src/assets/terminal/discard-all-changes.png differ diff --git a/src/assets/terminal/docker-extension.png b/src/assets/terminal/docker-extension.png new file mode 100644 index 0000000..77ea093 Binary files /dev/null and b/src/assets/terminal/docker-extension.png differ diff --git a/src/assets/terminal/dracula.png b/src/assets/terminal/dracula.png new file mode 100644 index 0000000..1e0219a Binary files /dev/null and b/src/assets/terminal/dracula.png differ diff --git a/src/assets/terminal/edit-prompt-modal.png b/src/assets/terminal/edit-prompt-modal.png new file mode 100644 index 0000000..8ed66a0 Binary files /dev/null and b/src/assets/terminal/edit-prompt-modal.png differ diff --git a/src/assets/terminal/edit-workflow-pane.png b/src/assets/terminal/edit-workflow-pane.png new file mode 100644 index 0000000..ac0ba78 Binary files /dev/null and b/src/assets/terminal/edit-workflow-pane.png differ diff --git a/src/assets/terminal/embed.png b/src/assets/terminal/embed.png new file mode 100644 index 0000000..d9229fc Binary files /dev/null and b/src/assets/terminal/embed.png differ diff --git a/src/assets/terminal/embedding-a-workflow.png b/src/assets/terminal/embedding-a-workflow.png new file mode 100644 index 0000000..fd9bc4d Binary files /dev/null and b/src/assets/terminal/embedding-a-workflow.png differ diff --git a/src/assets/terminal/env-var-create.png b/src/assets/terminal/env-var-create.png new file mode 100644 index 0000000..6003162 Binary files /dev/null and b/src/assets/terminal/env-var-create.png differ diff --git a/src/assets/terminal/env-var-dynamic-variables.png b/src/assets/terminal/env-var-dynamic-variables.png new file mode 100644 index 0000000..a21c85e Binary files /dev/null and b/src/assets/terminal/env-var-dynamic-variables.png differ diff --git a/src/assets/terminal/env-var-load-in-session.png b/src/assets/terminal/env-var-load-in-session.png new file mode 100644 index 0000000..1700f9b Binary files /dev/null and b/src/assets/terminal/env-var-load-in-session.png differ diff --git a/src/assets/terminal/env-var-load-to-input-1.png b/src/assets/terminal/env-var-load-to-input-1.png new file mode 100644 index 0000000..72be659 Binary files /dev/null and b/src/assets/terminal/env-var-load-to-input-1.png differ diff --git a/src/assets/terminal/env-var-password-mgrs.png b/src/assets/terminal/env-var-password-mgrs.png new file mode 100644 index 0000000..a2842e0 Binary files /dev/null and b/src/assets/terminal/env-var-password-mgrs.png differ diff --git a/src/assets/terminal/env-var-static-variable-load.png b/src/assets/terminal/env-var-static-variable-load.png new file mode 100644 index 0000000..84d2941 Binary files /dev/null and b/src/assets/terminal/env-var-static-variable-load.png differ diff --git a/src/assets/terminal/env-var-static-variable-save.png b/src/assets/terminal/env-var-static-variable-save.png new file mode 100644 index 0000000..9d2ebaf Binary files /dev/null and b/src/assets/terminal/env-var-static-variable-save.png differ diff --git a/src/assets/terminal/execute-a-workflow.png b/src/assets/terminal/execute-a-workflow.png new file mode 100644 index 0000000..b41e3c7 Binary files /dev/null and b/src/assets/terminal/execute-a-workflow.png differ diff --git a/src/assets/terminal/fancy-dracula.png b/src/assets/terminal/fancy-dracula.png new file mode 100644 index 0000000..625611e Binary files /dev/null and b/src/assets/terminal/fancy-dracula.png differ diff --git a/src/assets/terminal/file-tree-context-menu.png b/src/assets/terminal/file-tree-context-menu.png new file mode 100644 index 0000000..6a53ac2 Binary files /dev/null and b/src/assets/terminal/file-tree-context-menu.png differ diff --git a/src/assets/terminal/file-tree-new-file.png b/src/assets/terminal/file-tree-new-file.png new file mode 100644 index 0000000..af5ce16 Binary files /dev/null and b/src/assets/terminal/file-tree-new-file.png differ diff --git a/src/assets/terminal/file-tree-project-explorer-tools-panel.png b/src/assets/terminal/file-tree-project-explorer-tools-panel.png new file mode 100644 index 0000000..b0938a3 Binary files /dev/null and b/src/assets/terminal/file-tree-project-explorer-tools-panel.png differ diff --git a/src/assets/terminal/filetree-main.png b/src/assets/terminal/filetree-main.png new file mode 100644 index 0000000..39320c4 Binary files /dev/null and b/src/assets/terminal/filetree-main.png differ diff --git a/src/assets/terminal/git-branch-chip.png b/src/assets/terminal/git-branch-chip.png new file mode 100644 index 0000000..e0404cd Binary files /dev/null and b/src/assets/terminal/git-branch-chip.png differ diff --git a/src/assets/terminal/git-chip-tooltip-1.png b/src/assets/terminal/git-chip-tooltip-1.png new file mode 100644 index 0000000..cf1d23a Binary files /dev/null and b/src/assets/terminal/git-chip-tooltip-1.png differ diff --git a/src/assets/terminal/git-diff-change-base-dropdown.png b/src/assets/terminal/git-diff-change-base-dropdown.png new file mode 100644 index 0000000..1e44143 Binary files /dev/null and b/src/assets/terminal/git-diff-change-base-dropdown.png differ diff --git a/src/assets/terminal/glass-sky-icon.png b/src/assets/terminal/glass-sky-icon.png new file mode 100644 index 0000000..6ede70b Binary files /dev/null and b/src/assets/terminal/glass-sky-icon.png differ diff --git a/src/assets/terminal/glitch-icon.png b/src/assets/terminal/glitch-icon.png new file mode 100644 index 0000000..5864365 Binary files /dev/null and b/src/assets/terminal/glitch-icon.png differ diff --git a/src/assets/terminal/glow-icon.png b/src/assets/terminal/glow-icon.png new file mode 100644 index 0000000..6652a65 Binary files /dev/null and b/src/assets/terminal/glow-icon.png differ diff --git a/src/assets/terminal/gruvbox-dark.png b/src/assets/terminal/gruvbox-dark.png new file mode 100644 index 0000000..f6e839e Binary files /dev/null and b/src/assets/terminal/gruvbox-dark.png differ diff --git a/src/assets/terminal/gruvbox-light.png b/src/assets/terminal/gruvbox-light.png new file mode 100644 index 0000000..94f2d3b Binary files /dev/null and b/src/assets/terminal/gruvbox-light.png differ diff --git a/src/assets/terminal/holographic-icon.png b/src/assets/terminal/holographic-icon.png new file mode 100644 index 0000000..d42a9b0 Binary files /dev/null and b/src/assets/terminal/holographic-icon.png differ diff --git a/src/assets/terminal/images-as-context-chip.png b/src/assets/terminal/images-as-context-chip.png new file mode 100644 index 0000000..7d042eb Binary files /dev/null and b/src/assets/terminal/images-as-context-chip.png differ diff --git a/src/assets/terminal/input-toolbar.png b/src/assets/terminal/input-toolbar.png new file mode 100644 index 0000000..355d68a Binary files /dev/null and b/src/assets/terminal/input-toolbar.png differ diff --git a/src/assets/terminal/jellyfish.png b/src/assets/terminal/jellyfish.png new file mode 100644 index 0000000..d42e247 Binary files /dev/null and b/src/assets/terminal/jellyfish.png differ diff --git a/src/assets/terminal/keybinds-conflict.png b/src/assets/terminal/keybinds-conflict.png new file mode 100644 index 0000000..b1deaff Binary files /dev/null and b/src/assets/terminal/keybinds-conflict.png differ diff --git a/src/assets/terminal/koi.png b/src/assets/terminal/koi.png new file mode 100644 index 0000000..d7f6bf7 Binary files /dev/null and b/src/assets/terminal/koi.png differ diff --git a/src/assets/terminal/leafy.png b/src/assets/terminal/leafy.png new file mode 100644 index 0000000..70e5bf4 Binary files /dev/null and b/src/assets/terminal/leafy.png differ diff --git a/src/assets/terminal/marble.png b/src/assets/terminal/marble.png new file mode 100644 index 0000000..09d390f Binary files /dev/null and b/src/assets/terminal/marble.png differ diff --git a/src/assets/terminal/markdown-element-types.png b/src/assets/terminal/markdown-element-types.png new file mode 100644 index 0000000..bace71e Binary files /dev/null and b/src/assets/terminal/markdown-element-types.png differ diff --git a/src/assets/terminal/migrate-to-warp.png b/src/assets/terminal/migrate-to-warp.png new file mode 100644 index 0000000..355fb38 Binary files /dev/null and b/src/assets/terminal/migrate-to-warp.png differ diff --git a/src/assets/terminal/mono-icon.png b/src/assets/terminal/mono-icon.png new file mode 100644 index 0000000..42acf2b Binary files /dev/null and b/src/assets/terminal/mono-icon.png differ diff --git a/src/assets/terminal/moody-dev-default-icon.png b/src/assets/terminal/moody-dev-default-icon.png new file mode 100644 index 0000000..52bddd7 Binary files /dev/null and b/src/assets/terminal/moody-dev-default-icon.png differ diff --git a/src/assets/terminal/multi-agents.png b/src/assets/terminal/multi-agents.png new file mode 100644 index 0000000..f5f53cc Binary files /dev/null and b/src/assets/terminal/multi-agents.png differ diff --git a/src/assets/terminal/neon-icon.png b/src/assets/terminal/neon-icon.png new file mode 100644 index 0000000..d593827 Binary files /dev/null and b/src/assets/terminal/neon-icon.png differ diff --git a/src/assets/terminal/node-version-chip.png b/src/assets/terminal/node-version-chip.png new file mode 100644 index 0000000..70bfe90 Binary files /dev/null and b/src/assets/terminal/node-version-chip.png differ diff --git a/src/assets/terminal/notebook-cmd-block-run.png b/src/assets/terminal/notebook-cmd-block-run.png new file mode 100644 index 0000000..a6dd0c1 Binary files /dev/null and b/src/assets/terminal/notebook-cmd-block-run.png differ diff --git a/src/assets/terminal/notebook-cmd-with-params.png b/src/assets/terminal/notebook-cmd-with-params.png new file mode 100644 index 0000000..7dd0793 Binary files /dev/null and b/src/assets/terminal/notebook-cmd-with-params.png differ diff --git a/src/assets/terminal/notebook-code-block.png b/src/assets/terminal/notebook-code-block.png new file mode 100644 index 0000000..74d6ea0 Binary files /dev/null and b/src/assets/terminal/notebook-code-block.png differ diff --git a/src/assets/terminal/notebook-import-modal.png b/src/assets/terminal/notebook-import-modal.png new file mode 100644 index 0000000..74cb6c7 Binary files /dev/null and b/src/assets/terminal/notebook-import-modal.png differ diff --git a/src/assets/terminal/notebook-view-mode.png b/src/assets/terminal/notebook-view-mode.png new file mode 100644 index 0000000..f50062b Binary files /dev/null and b/src/assets/terminal/notebook-view-mode.png differ diff --git a/src/assets/terminal/original-icon.png b/src/assets/terminal/original-icon.png new file mode 100644 index 0000000..bd37029 Binary files /dev/null and b/src/assets/terminal/original-icon.png differ diff --git a/src/assets/terminal/p10k-grey-arrow-prompt.png b/src/assets/terminal/p10k-grey-arrow-prompt.png new file mode 100644 index 0000000..3a6ac0a Binary files /dev/null and b/src/assets/terminal/p10k-grey-arrow-prompt.png differ diff --git a/src/assets/terminal/padding-settings.png b/src/assets/terminal/padding-settings.png new file mode 100644 index 0000000..f389a59 Binary files /dev/null and b/src/assets/terminal/padding-settings.png differ diff --git a/src/assets/terminal/phenomenon.png b/src/assets/terminal/phenomenon.png new file mode 100644 index 0000000..d94d4ec Binary files /dev/null and b/src/assets/terminal/phenomenon.png differ diff --git a/src/assets/terminal/pink-city.png b/src/assets/terminal/pink-city.png new file mode 100644 index 0000000..c9c84d0 Binary files /dev/null and b/src/assets/terminal/pink-city.png differ diff --git a/src/assets/terminal/prompts-command-palette.png b/src/assets/terminal/prompts-command-palette.png new file mode 100644 index 0000000..390738e Binary files /dev/null and b/src/assets/terminal/prompts-command-palette.png differ diff --git a/src/assets/terminal/prompts-command-search.png b/src/assets/terminal/prompts-command-search.png new file mode 100644 index 0000000..b88aa05 Binary files /dev/null and b/src/assets/terminal/prompts-command-search.png differ diff --git a/src/assets/terminal/prompts-command-view.png b/src/assets/terminal/prompts-command-view.png new file mode 100644 index 0000000..4a7a759 Binary files /dev/null and b/src/assets/terminal/prompts-command-view.png differ diff --git a/src/assets/terminal/prompts-edit-view.png b/src/assets/terminal/prompts-edit-view.png new file mode 100644 index 0000000..b5f0aa5 Binary files /dev/null and b/src/assets/terminal/prompts-edit-view.png differ diff --git a/src/assets/terminal/raycast-terminal-tip.png b/src/assets/terminal/raycast-terminal-tip.png new file mode 100644 index 0000000..3d1d420 Binary files /dev/null and b/src/assets/terminal/raycast-terminal-tip.png differ diff --git a/src/assets/terminal/rectangular-selection.png b/src/assets/terminal/rectangular-selection.png new file mode 100644 index 0000000..98d2d2b Binary files /dev/null and b/src/assets/terminal/rectangular-selection.png differ diff --git a/src/assets/terminal/red-rock.png b/src/assets/terminal/red-rock.png new file mode 100644 index 0000000..8cb7c11 Binary files /dev/null and b/src/assets/terminal/red-rock.png differ diff --git a/src/assets/terminal/revert-diff-hunk.png b/src/assets/terminal/revert-diff-hunk.png new file mode 100644 index 0000000..f53f691 Binary files /dev/null and b/src/assets/terminal/revert-diff-hunk.png differ diff --git a/src/assets/terminal/review-changes-in-footer.png b/src/assets/terminal/review-changes-in-footer.png new file mode 100644 index 0000000..593ea47 Binary files /dev/null and b/src/assets/terminal/review-changes-in-footer.png differ diff --git a/src/assets/terminal/save-new-tab-config.png b/src/assets/terminal/save-new-tab-config.png new file mode 100644 index 0000000..615f861 Binary files /dev/null and b/src/assets/terminal/save-new-tab-config.png differ diff --git a/src/assets/terminal/saved-tab-config-menu.png b/src/assets/terminal/saved-tab-config-menu.png new file mode 100644 index 0000000..c4f05e7 Binary files /dev/null and b/src/assets/terminal/saved-tab-config-menu.png differ diff --git a/src/assets/terminal/search-files-icon.png b/src/assets/terminal/search-files-icon.png new file mode 100644 index 0000000..68913a0 Binary files /dev/null and b/src/assets/terminal/search-files-icon.png differ diff --git a/src/assets/terminal/search-workflow-command-palette.png b/src/assets/terminal/search-workflow-command-palette.png new file mode 100644 index 0000000..375626c Binary files /dev/null and b/src/assets/terminal/search-workflow-command-palette.png differ diff --git a/src/assets/terminal/settings-not-synced.png b/src/assets/terminal/settings-not-synced.png new file mode 100644 index 0000000..697734a Binary files /dev/null and b/src/assets/terminal/settings-not-synced.png differ diff --git a/src/assets/terminal/settings-sync-account.png b/src/assets/terminal/settings-sync-account.png new file mode 100644 index 0000000..6629864 Binary files /dev/null and b/src/assets/terminal/settings-sync-account.png differ diff --git a/src/assets/terminal/settings-sync-palette.png b/src/assets/terminal/settings-sync-palette.png new file mode 100644 index 0000000..15ccabe Binary files /dev/null and b/src/assets/terminal/settings-sync-palette.png differ diff --git a/src/assets/terminal/shared_block.png b/src/assets/terminal/shared_block.png new file mode 100644 index 0000000..221d43e Binary files /dev/null and b/src/assets/terminal/shared_block.png differ diff --git a/src/assets/terminal/smart-selection.png b/src/assets/terminal/smart-selection.png new file mode 100644 index 0000000..193352c Binary files /dev/null and b/src/assets/terminal/smart-selection.png differ diff --git a/src/assets/terminal/snowy.png b/src/assets/terminal/snowy.png new file mode 100644 index 0000000..aeb0783 Binary files /dev/null and b/src/assets/terminal/snowy.png differ diff --git a/src/assets/terminal/soft-wrapping.png b/src/assets/terminal/soft-wrapping.png new file mode 100644 index 0000000..e80844a Binary files /dev/null and b/src/assets/terminal/soft-wrapping.png differ diff --git a/src/assets/terminal/solar-flare.png b/src/assets/terminal/solar-flare.png new file mode 100644 index 0000000..be7d03d Binary files /dev/null and b/src/assets/terminal/solar-flare.png differ diff --git a/src/assets/terminal/solarized-dark.png b/src/assets/terminal/solarized-dark.png new file mode 100644 index 0000000..67eab27 Binary files /dev/null and b/src/assets/terminal/solarized-dark.png differ diff --git a/src/assets/terminal/solarized-light.png b/src/assets/terminal/solarized-light.png new file mode 100644 index 0000000..b039867 Binary files /dev/null and b/src/assets/terminal/solarized-light.png differ diff --git a/src/assets/terminal/ssh-1.png b/src/assets/terminal/ssh-1.png new file mode 100644 index 0000000..d1dfbe0 Binary files /dev/null and b/src/assets/terminal/ssh-1.png differ diff --git a/src/assets/terminal/starburst-icon.png b/src/assets/terminal/starburst-icon.png new file mode 100644 index 0000000..6c51867 Binary files /dev/null and b/src/assets/terminal/starburst-icon.png differ diff --git a/src/assets/terminal/sticker-icon.png b/src/assets/terminal/sticker-icon.png new file mode 100644 index 0000000..c4485a4 Binary files /dev/null and b/src/assets/terminal/sticker-icon.png differ diff --git a/src/assets/terminal/styling-menu.png b/src/assets/terminal/styling-menu.png new file mode 100644 index 0000000..a44f76d Binary files /dev/null and b/src/assets/terminal/styling-menu.png differ diff --git a/src/assets/terminal/tab-hover-detail-card.png b/src/assets/terminal/tab-hover-detail-card.png new file mode 100644 index 0000000..cf0ae7f Binary files /dev/null and b/src/assets/terminal/tab-hover-detail-card.png differ diff --git a/src/assets/terminal/tabbed-file-viewer.png b/src/assets/terminal/tabbed-file-viewer.png new file mode 100644 index 0000000..30d23d4 Binary files /dev/null and b/src/assets/terminal/tabbed-file-viewer.png differ diff --git a/src/assets/terminal/team-creation-settings.png b/src/assets/terminal/team-creation-settings.png new file mode 100644 index 0000000..912c5f1 Binary files /dev/null and b/src/assets/terminal/team-creation-settings.png differ diff --git a/src/assets/terminal/teams-invite-demo.png b/src/assets/terminal/teams-invite-demo.png new file mode 100644 index 0000000..b8ce320 Binary files /dev/null and b/src/assets/terminal/teams-invite-demo.png differ diff --git a/src/assets/terminal/termbench_regular.png b/src/assets/terminal/termbench_regular.png new file mode 100644 index 0000000..fed348f Binary files /dev/null and b/src/assets/terminal/termbench_regular.png differ diff --git a/src/assets/terminal/termbench_small.png b/src/assets/terminal/termbench_small.png new file mode 100644 index 0000000..f9dfb02 Binary files /dev/null and b/src/assets/terminal/termbench_small.png differ diff --git a/src/assets/terminal/undo_my_git_commit.png b/src/assets/terminal/undo_my_git_commit.png new file mode 100644 index 0000000..f886e83 Binary files /dev/null and b/src/assets/terminal/undo_my_git_commit.png differ diff --git a/src/assets/terminal/universal-input-header.png b/src/assets/terminal/universal-input-header.png new file mode 100644 index 0000000..766a60f Binary files /dev/null and b/src/assets/terminal/universal-input-header.png differ diff --git a/src/assets/terminal/universal-input-terminal-mode.png b/src/assets/terminal/universal-input-terminal-mode.png new file mode 100644 index 0000000..333abe5 Binary files /dev/null and b/src/assets/terminal/universal-input-terminal-mode.png differ diff --git a/src/assets/terminal/universal-input.png b/src/assets/terminal/universal-input.png new file mode 100644 index 0000000..d17dca1 Binary files /dev/null and b/src/assets/terminal/universal-input.png differ diff --git a/src/assets/terminal/using-agents-universal-input.png b/src/assets/terminal/using-agents-universal-input.png new file mode 100644 index 0000000..459e3d0 Binary files /dev/null and b/src/assets/terminal/using-agents-universal-input.png differ diff --git a/src/assets/terminal/vertical-tab-settings.png b/src/assets/terminal/vertical-tab-settings.png new file mode 100644 index 0000000..85e7775 Binary files /dev/null and b/src/assets/terminal/vertical-tab-settings.png differ diff --git a/src/assets/terminal/vertical-tabs-condensed.png b/src/assets/terminal/vertical-tabs-condensed.png new file mode 100644 index 0000000..81210d2 Binary files /dev/null and b/src/assets/terminal/vertical-tabs-condensed.png differ diff --git a/src/assets/terminal/vertical-tabs-multi-agent.png b/src/assets/terminal/vertical-tabs-multi-agent.png new file mode 100644 index 0000000..c1433bf Binary files /dev/null and b/src/assets/terminal/vertical-tabs-multi-agent.png differ diff --git a/src/assets/terminal/vtebench_avg.png b/src/assets/terminal/vtebench_avg.png new file mode 100644 index 0000000..4fd6246 Binary files /dev/null and b/src/assets/terminal/vtebench_avg.png differ diff --git a/src/assets/terminal/vtebench_p90.png b/src/assets/terminal/vtebench_p90.png new file mode 100644 index 0000000..2ff8b63 Binary files /dev/null and b/src/assets/terminal/vtebench_p90.png differ diff --git a/src/assets/terminal/warp-ai-permissions.png b/src/assets/terminal/warp-ai-permissions.png new file mode 100644 index 0000000..6872236 Binary files /dev/null and b/src/assets/terminal/warp-ai-permissions.png differ diff --git a/src/assets/terminal/warp-ai-viewing-commands.png b/src/assets/terminal/warp-ai-viewing-commands.png new file mode 100644 index 0000000..85e9e1e Binary files /dev/null and b/src/assets/terminal/warp-ai-viewing-commands.png differ diff --git a/src/assets/terminal/warp-dark.png b/src/assets/terminal/warp-dark.png new file mode 100644 index 0000000..72c990c Binary files /dev/null and b/src/assets/terminal/warp-dark.png differ diff --git a/src/assets/terminal/warp-light.png b/src/assets/terminal/warp-light.png new file mode 100644 index 0000000..b0abfd1 Binary files /dev/null and b/src/assets/terminal/warp-light.png differ diff --git a/src/assets/terminal/warp-oz-welcome.png b/src/assets/terminal/warp-oz-welcome.png new file mode 100644 index 0000000..6224a45 Binary files /dev/null and b/src/assets/terminal/warp-oz-welcome.png differ diff --git a/src/assets/terminal/warp_drive_nav1.png b/src/assets/terminal/warp_drive_nav1.png new file mode 100644 index 0000000..b270a22 Binary files /dev/null and b/src/assets/terminal/warp_drive_nav1.png differ diff --git a/src/assets/terminal/warp_drive_nav2.png b/src/assets/terminal/warp_drive_nav2.png new file mode 100644 index 0000000..c471c8a Binary files /dev/null and b/src/assets/terminal/warp_drive_nav2.png differ diff --git a/src/assets/terminal/warp_drive_offline.png b/src/assets/terminal/warp_drive_offline.png new file mode 100644 index 0000000..09dfac9 Binary files /dev/null and b/src/assets/terminal/warp_drive_offline.png differ diff --git a/src/assets/terminal/warpify_ssh_auto_script.png b/src/assets/terminal/warpify_ssh_auto_script.png new file mode 100644 index 0000000..b2a6821 Binary files /dev/null and b/src/assets/terminal/warpify_ssh_auto_script.png differ diff --git a/src/assets/terminal/warpify_ssh_prompt.png b/src/assets/terminal/warpify_ssh_prompt.png new file mode 100644 index 0000000..d750cd2 Binary files /dev/null and b/src/assets/terminal/warpify_ssh_prompt.png differ diff --git a/src/assets/terminal/wd-copy-link-menu.png b/src/assets/terminal/wd-copy-link-menu.png new file mode 100644 index 0000000..cf376fa Binary files /dev/null and b/src/assets/terminal/wd-copy-link-menu.png differ diff --git a/src/assets/terminal/wd-open-links-preference.png b/src/assets/terminal/wd-open-links-preference.png new file mode 100644 index 0000000..b94827a Binary files /dev/null and b/src/assets/terminal/wd-open-links-preference.png differ diff --git a/src/assets/terminal/wd-popup-message.png b/src/assets/terminal/wd-popup-message.png new file mode 100644 index 0000000..6c15d2a Binary files /dev/null and b/src/assets/terminal/wd-popup-message.png differ diff --git a/src/assets/terminal/wd-share-button.png b/src/assets/terminal/wd-share-button.png new file mode 100644 index 0000000..f914bba Binary files /dev/null and b/src/assets/terminal/wd-share-button.png differ diff --git a/src/assets/terminal/wd-share-dialog.png b/src/assets/terminal/wd-share-dialog.png new file mode 100644 index 0000000..6b2434f Binary files /dev/null and b/src/assets/terminal/wd-share-dialog.png differ diff --git a/src/assets/terminal/wd-switch-viewer.png b/src/assets/terminal/wd-switch-viewer.png new file mode 100644 index 0000000..2d8b447 Binary files /dev/null and b/src/assets/terminal/wd-switch-viewer.png differ diff --git a/src/assets/terminal/wd-view-on-web.png b/src/assets/terminal/wd-view-on-web.png new file mode 100644 index 0000000..43d213d Binary files /dev/null and b/src/assets/terminal/wd-view-on-web.png differ diff --git a/src/assets/terminal/wd-web-team-workflow.png b/src/assets/terminal/wd-web-team-workflow.png new file mode 100644 index 0000000..52d2100 Binary files /dev/null and b/src/assets/terminal/wd-web-team-workflow.png differ diff --git a/src/assets/terminal/whole-UDI-bar.png b/src/assets/terminal/whole-UDI-bar.png new file mode 100644 index 0000000..7c440f8 Binary files /dev/null and b/src/assets/terminal/whole-UDI-bar.png differ diff --git a/src/assets/terminal/whole-git-diff-view-with-one-file-collapsed.png b/src/assets/terminal/whole-git-diff-view-with-one-file-collapsed.png new file mode 100644 index 0000000..6b0cfb0 Binary files /dev/null and b/src/assets/terminal/whole-git-diff-view-with-one-file-collapsed.png differ diff --git a/src/assets/terminal/willow-dream.png b/src/assets/terminal/willow-dream.png new file mode 100644 index 0000000..aab7a9f Binary files /dev/null and b/src/assets/terminal/willow-dream.png differ diff --git a/src/assets/terminal/zero-state-universal-input.png b/src/assets/terminal/zero-state-universal-input.png new file mode 100644 index 0000000..d5dcbeb Binary files /dev/null and b/src/assets/terminal/zero-state-universal-input.png differ diff --git a/src/assets/warp-logo-dark.svg b/src/assets/warp-logo-dark.svg new file mode 100644 index 0000000..9cc17ea --- /dev/null +++ b/src/assets/warp-logo-dark.svg @@ -0,0 +1,5 @@ +<svg viewBox="91 26 592 135" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M170.286 27.5005H227.682C236.973 27.5005 244.505 35.2835 244.505 44.8844V112.374C244.505 121.975 236.973 129.758 227.682 129.758H145.546L170.286 27.5005Z" fill="#FAF9F6"/> +<path d="M155.378 46.8732H109.141C99.9291 46.8732 92.4613 54.6562 92.4613 64.257V131.747C92.4613 141.348 99.9291 149.131 109.141 149.131H166.048L168.33 139.618H133.131L155.378 46.8732Z" fill="#FAF9F6"/> +<path d="M313.427 129.717L288.122 46.9034H302.418L320.328 110.164L339.717 46.9034H353.19L372.58 110.164L390.325 46.9034H404.949L379.481 129.717H365.843L346.454 66.7853L327.065 129.717H313.427ZM467.986 75.8225C467.986 64.4849 459.935 57.2551 447.776 57.2551C436.438 57.2551 428.387 63.992 427.237 75.1653L414.256 72.7006C416.721 56.2692 430.359 45.5889 447.776 45.5889C467.822 45.5889 481.789 57.4194 481.789 76.6441V129.717H467.986V115.586C463.221 125.117 452.377 131.032 440.382 131.032C423.786 131.032 412.449 120.844 412.449 106.549C412.449 90.6107 425.429 81.9021 451.884 79.2731L467.986 77.4657V75.8225ZM426.415 106.385C426.415 114.108 432.988 119.53 442.518 119.53C458.621 119.53 467.986 108.849 467.986 92.2539V88.3103L451.884 90.1178C435.124 91.9252 426.415 97.6762 426.415 106.385ZM575.81 75.001L561.843 77.63C561.186 65.3065 553.463 58.241 540.975 58.241C525.694 58.241 515.835 72.0433 515.835 94.2256V129.717H501.869V46.9034H515.835V63.1704C521.915 51.3398 532.102 45.5889 544.262 45.5889C562.665 45.5889 575.152 57.0908 575.81 75.001ZM590.697 159.622V46.9034H604.664V58.8982C609.1 51.3398 619.945 45.5889 631.94 45.5889C657.408 45.5889 671.539 63.992 671.539 88.3103C671.539 112.629 657.08 131.032 631.611 131.032C621.095 131.032 610.251 125.774 604.664 118.215V159.622H590.697ZM630.297 118.544C646.728 118.544 657.408 106.549 657.408 88.3103C657.408 70.0716 646.728 58.0767 630.297 58.0767C614.194 58.0767 603.514 70.0716 603.514 88.3103C603.514 106.549 614.194 118.544 630.297 118.544Z" fill="#FAF9F6"/> +</svg> diff --git a/src/assets/warp-logo-light.svg b/src/assets/warp-logo-light.svg new file mode 100644 index 0000000..324ef18 --- /dev/null +++ b/src/assets/warp-logo-light.svg @@ -0,0 +1,5 @@ +<svg viewBox="91 26 592 135" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M170.286 27.5005H227.682C236.973 27.5005 244.505 35.2835 244.505 44.8844V112.374C244.505 121.975 236.973 129.758 227.682 129.758H145.546L170.286 27.5005Z" fill="#121212"/> +<path d="M155.378 46.8732H109.141C99.9291 46.8732 92.4613 54.6562 92.4613 64.257V131.747C92.4613 141.348 99.9291 149.131 109.141 149.131H166.048L168.33 139.618H133.131L155.378 46.8732Z" fill="#121212"/> +<path d="M313.427 129.717L288.122 46.9034H302.418L320.328 110.164L339.717 46.9034H353.19L372.58 110.164L390.325 46.9034H404.949L379.481 129.717H365.843L346.454 66.7853L327.065 129.717H313.427ZM467.986 75.8225C467.986 64.4849 459.935 57.2551 447.776 57.2551C436.438 57.2551 428.387 63.992 427.237 75.1653L414.256 72.7006C416.721 56.2692 430.359 45.5889 447.776 45.5889C467.822 45.5889 481.789 57.4194 481.789 76.6441V129.717H467.986V115.586C463.221 125.117 452.377 131.032 440.382 131.032C423.786 131.032 412.449 120.844 412.449 106.549C412.449 90.6107 425.429 81.9021 451.884 79.2731L467.986 77.4657V75.8225ZM426.415 106.385C426.415 114.108 432.988 119.53 442.518 119.53C458.621 119.53 467.986 108.849 467.986 92.2539V88.3103L451.884 90.1178C435.124 91.9252 426.415 97.6762 426.415 106.385ZM575.81 75.001L561.843 77.63C561.186 65.3065 553.463 58.241 540.975 58.241C525.694 58.241 515.835 72.0433 515.835 94.2256V129.717H501.869V46.9034H515.835V63.1704C521.915 51.3398 532.102 45.5889 544.262 45.5889C562.665 45.5889 575.152 57.0908 575.81 75.001ZM590.697 159.622V46.9034H604.664V58.8982C609.1 51.3398 619.945 45.5889 631.94 45.5889C657.408 45.5889 671.539 63.992 671.539 88.3103C671.539 112.629 657.08 131.032 631.611 131.032C621.095 131.032 610.251 125.774 604.664 118.215V159.622H590.697ZM630.297 118.544C646.728 118.544 657.408 106.549 657.408 88.3103C657.408 70.0716 646.728 58.0767 630.297 58.0767C614.194 58.0767 603.514 70.0716 603.514 88.3103C603.514 106.549 614.194 118.544 630.297 118.544Z" fill="#121212"/> +</svg> diff --git a/src/components/CopyPageButton.astro b/src/components/CopyPageButton.astro new file mode 100644 index 0000000..71cb7ed --- /dev/null +++ b/src/components/CopyPageButton.astro @@ -0,0 +1,384 @@ +--- +/** + * CopyPageButton — Scalar-style dropdown with: + * - Copy page (copies raw MDX body as markdown) + * - View as Markdown (opens .md URL in new tab) + * - Export as PDF (window.print) + */ +interface Props { + body: string; + title: string; +} +const { body, title } = Astro.props; +const markdownContent = `# ${title}\n\n${body}`; +const pageUrl = Astro.url.href; +const prompt = encodeURIComponent(`Read ${pageUrl}. I want to ask questions about it.`); +const chatgptUrl = `https://chatgpt.com/?q=${prompt}`; +const claudeUrl = `https://claude.ai/new?q=${prompt}`; +--- + +<div class="copy-dropdown-wrapper" id="copy-dropdown-wrapper"> + <button class="copy-dropdown-trigger" id="copy-dropdown-trigger"> + <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> + <rect width="14" height="14" x="8" y="8" rx="2" ry="2"/> + <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/> + </svg> + <span>Copy</span> + <svg class="chevron" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"> + <path d="m6 9 6 6 6-6"/> + </svg> + </button> + + <div class="copy-dropdown-panel" id="copy-dropdown-panel"> + <button class="copy-dropdown-item" id="copy-as-markdown"> + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> + <rect width="14" height="14" x="8" y="8" rx="2" ry="2"/> + <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/> + </svg> + <div> + <div class="item-label">Copy page</div> + <div class="item-desc">Copy page as Markdown for LLMs</div> + </div> + </button> + + <button class="copy-dropdown-item" id="view-as-markdown"> + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> + <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/> + <polyline points="14 2 14 8 20 8"/> + <line x1="16" y1="13" x2="8" y2="13"/> + <line x1="16" y1="17" x2="8" y2="17"/> + <polyline points="10 9 9 9 8 9"/> + </svg> + <div> + <div class="item-label">View as Markdown ↗</div> + <div class="item-desc">View this page as plain text</div> + </div> + </button> + + <div class="dropdown-divider"></div> + + <a class="copy-dropdown-item" href={chatgptUrl} target="_blank" rel="noopener"> + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor"> + <path d="M22.28 9.37a5.98 5.98 0 0 0-.52-4.93 6.07 6.07 0 0 0-6.55-2.74A5.97 5.97 0 0 0 10.7.15a6.07 6.07 0 0 0-5.8 4.22 5.98 5.98 0 0 0-4 2.89 6.07 6.07 0 0 0 .74 7.11 5.98 5.98 0 0 0 .52 4.93 6.07 6.07 0 0 0 6.55 2.74 5.97 5.97 0 0 0 4.51 1.55 6.07 6.07 0 0 0 5.8-4.22 5.98 5.98 0 0 0 4-2.89 6.07 6.07 0 0 0-.74-7.11ZM13.3 22.18a4.49 4.49 0 0 1-2.88-1.04l.14-.08 4.79-2.77a.78.78 0 0 0 .39-.68v-6.76l2.02 1.17a.07.07 0 0 1 .04.06v5.6a4.52 4.52 0 0 1-4.5 4.5ZM3.6 18.11a4.49 4.49 0 0 1-.54-3.02l.14.09 4.79 2.76a.78.78 0 0 0 .78 0l5.85-3.38v2.33a.07.07 0 0 1-.03.06l-4.84 2.8a4.52 4.52 0 0 1-6.15-1.64ZM2.34 7.89a4.49 4.49 0 0 1 2.35-1.98v5.71a.78.78 0 0 0 .39.68l5.85 3.37-2.02 1.17a.07.07 0 0 1-.07 0l-4.84-2.8A4.52 4.52 0 0 1 2.34 7.9Zm17.33 4.03-5.85-3.38 2.02-1.16a.07.07 0 0 1 .07 0l4.84 2.8a4.52 4.52 0 0 1-.69 8.14v-5.72a.78.78 0 0 0-.39-.68Zm2.01-3.04-.14-.09-4.79-2.76a.78.78 0 0 0-.78 0L10.12 9.4V7.07a.07.07 0 0 1 .03-.06l4.84-2.8a4.52 4.52 0 0 1 6.69 4.67ZM8.92 12.98l-2.03-1.17a.07.07 0 0 1-.03-.06V6.15a4.52 4.52 0 0 1 7.38-3.47l-.14.08-4.79 2.77a.78.78 0 0 0-.39.68v6.77Zm1.1-2.37 2.6-1.5 2.6 1.5v3l-2.6 1.5-2.6-1.5v-3Z"/> + </svg> + <div> + <div class="item-label">Open in ChatGPT ↗</div> + <div class="item-desc">Ask ChatGPT about this page</div> + </div> + </a> + + <a class="copy-dropdown-item" href={claudeUrl} target="_blank" rel="noopener"> + {/* Official Claude (Anthropic) symbol — stylized starburst mark. + Source: simple-icons (https://github.com/simple-icons/simple-icons/blob/develop/icons/claude.svg). + Trademark of Anthropic; used here as a small in-line link affordance. */} + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"> + <path d="m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z"/> + </svg> + <div> + <div class="item-label">Open in Claude ↗</div> + <div class="item-desc">Ask Claude about this page</div> + </div> + </a> + + <div class="dropdown-divider"></div> + + <button class="copy-dropdown-item" id="export-as-pdf"> + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> + <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/> + <polyline points="14 2 14 8 20 8"/> + <line x1="12" y1="18" x2="12" y2="12"/> + <polyline points="9 15 12 18 15 15"/> + </svg> + <div> + <div class="item-label">Export as PDF</div> + <div class="item-desc">Save or print this page</div> + </div> + </button> + </div> + + <span class="copy-toast" id="copy-toast">Copied!</span> +</div> + +<!-- Store the markdown content in a hidden element so client JS can read it --> +<template id="page-markdown-content">{markdownContent}</template> + +<script> + // `DOMContentLoaded` is used instead of `astro:page-load` because + // `<ClientRouter />` is not enabled site-wide (see CustomHead.astro). + // `astro:page-load` only fires when View Transitions are active. + function initCopyDropdown() { + const wrapper = document.getElementById('copy-dropdown-wrapper'); + const trigger = document.getElementById('copy-dropdown-trigger'); + const panel = document.getElementById('copy-dropdown-panel'); + const toast = document.getElementById('copy-toast'); + const copyBtn = document.getElementById('copy-as-markdown'); + const viewMdBtn = document.getElementById('view-as-markdown'); + const exportBtn = document.getElementById('export-as-pdf'); + const mdTemplate = document.getElementById('page-markdown-content') as HTMLTemplateElement | null; + + if (!wrapper || !trigger || !panel) return; + + // Toggle dropdown + trigger.addEventListener('click', (e) => { + e.stopPropagation(); + panel.classList.toggle('open'); + trigger.classList.toggle('active'); + if (panel.classList.contains('open')) { + setTimeout(() => document.addEventListener('click', closeOnOutsideClick), 0); + } + }); + + function closeOnOutsideClick(e: MouseEvent) { + if (!wrapper?.contains(e.target as Node)) { + panel?.classList.remove('open'); + trigger?.classList.remove('active'); + document.removeEventListener('click', closeOnOutsideClick); + } + } + + // Copy page as Markdown — reads from the template element (raw MDX body). + // Use `template.content.textContent` because `<template>` children live in + // the DocumentFragment, not as direct children of the element itself, + // so `template.textContent` returns an empty string. + // + // The site is served over HTTPS and the click is a user-gesture handler, + // so `navigator.clipboard.writeText` is the only path we need — we + // previously had a `document.execCommand('copy')` textarea fallback for + // legacy browsers, but that path is deprecated, broken on iOS Safari, + // and never actually runs in production. + copyBtn?.addEventListener('click', async () => { + const markdown = mdTemplate?.content.textContent || ''; + if (markdown) { + try { + await navigator.clipboard.writeText(markdown); + showToast(); + } catch { + // Permission denied / insecure context — fail silently rather than + // copy nothing and pretend it worked. + } + } + panel?.classList.remove('open'); + trigger?.classList.remove('active'); + }); + + // View as Markdown — prefer the `.md` URL (shareable, stable path). + // The `[...slug].md.ts` endpoint serves it in dev; in prod the build-time + // docs-markdown integration writes it as a static file. If for any reason + // the `.md` URL isn't available, fall back to a Blob URL built from the + // raw body passed as a prop. + viewMdBtn?.addEventListener('click', async () => { + panel?.classList.remove('open'); + trigger?.classList.remove('active'); + + const path = window.location.pathname.replace(/\/$/, '') || '/index'; + const mdUrl = path + '.md'; + + // Probe the .md URL with a HEAD request. If it responds OK, navigate there. + try { + const res = await fetch(mdUrl, { method: 'HEAD' }); + if (res.ok) { + window.open(mdUrl, '_blank', 'noopener'); + return; + } + } catch { + // Fall through to the Blob URL fallback below. + } + + // Fallback: open the body directly as a Blob URL. + const markdown = mdTemplate?.content.textContent || ''; + if (markdown) { + const blob = new Blob([markdown], { type: 'text/markdown;charset=utf-8' }); + const blobUrl = URL.createObjectURL(blob); + window.open(blobUrl, '_blank', 'noopener'); + setTimeout(() => URL.revokeObjectURL(blobUrl), 60_000); + } + }); + + // Export as PDF + exportBtn?.addEventListener('click', () => { + panel?.classList.remove('open'); + trigger?.classList.remove('active'); + window.print(); + }); + + function showToast() { + toast?.classList.add('visible'); + setTimeout(() => toast?.classList.remove('visible'), 2000); + } + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', initCopyDropdown); + } else { + initCopyDropdown(); + } +</script> + +<style> + .copy-dropdown-wrapper { + position: relative; + display: inline-flex; + align-items: center; + margin-top: 1rem; + } + + /* Matches the Search + Ask paired-chrome pills via the shared + `--warp-control-*` palette (defined on `body` in warp-components.css + §16). Same surface, border, radius, type scale, and height — reads as + part of the same chrome system. Hard-coded fallbacks in each `var()` + keep the button rendering correctly even if the palette ever changes + scope or this component is lifted into a different page. */ + .copy-dropdown-trigger { + display: inline-flex; + align-items: center; + gap: 0.375rem; + height: 2.25rem; + padding: 0 0.625rem; + border: 1px solid var(--warp-control-border, hsl(210, 5%, 22%)); + border-radius: var(--sl-radius-sm); + background: var(--warp-control-bg, #1a1a1a); + color: var(--warp-control-text, hsl(210, 4%, 72%)); + font-family: var(--__sl-font, 'Inter', sans-serif); + font-size: var(--sl-text-sm); + font-weight: 400; + letter-spacing: 0; + line-height: 1; + cursor: pointer; + white-space: nowrap; + transition: + background-color 0.15s ease, + color 0.15s ease, + border-color 0.15s ease; + } + + .copy-dropdown-trigger:hover, + .copy-dropdown-trigger.active { + border-color: var(--warp-control-border-hover, hsl(210, 5%, 30%)); + background: var(--warp-control-bg-hover, hsl(210, 6%, 16%)); + color: var(--warp-control-text-hover, hsl(40, 20%, 97%)); + } + + .chevron { + transition: transform 0.15s ease; + } + + .copy-dropdown-trigger.active .chevron { + transform: rotate(180deg); + } + + .copy-dropdown-panel { + position: absolute; + top: calc(100% + 0.375rem); + right: 0; + min-width: 260px; + background: var(--sl-color-bg-nav); + border: 1px solid var(--sl-color-hairline-light); + border-radius: var(--sl-radius-lg); + padding: 0.375rem; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2); + opacity: 0; + visibility: hidden; + transform: translateY(-4px); + transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s ease; + z-index: 100; + } + + :root[data-theme='light'] .copy-dropdown-panel { + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08); + } + + .copy-dropdown-panel.open { + opacity: 1; + visibility: visible; + transform: translateY(0); + } + + .copy-dropdown-item { + display: flex; + align-items: flex-start; + gap: 0.625rem; + width: 100%; + padding: 0.5rem 0.625rem; + border: none; + border-radius: var(--sl-radius-md); + background: transparent; + color: var(--sl-color-white); + font-family: var(--sl-font); + font-size: var(--sl-text-sm); + text-align: left; + text-decoration: none; + cursor: pointer; + /* 0.15s matches the rest of the site's interactive transitions + (was 0.1s here, the only outlier). */ + transition: background-color 0.15s ease; + } + + .copy-dropdown-item:hover { + background-color: var(--sl-color-gray-5); + } + + :root[data-theme='light'] .copy-dropdown-item { + color: var(--sl-color-gray-1); + } + + :root[data-theme='light'] .copy-dropdown-item:hover { + background-color: var(--sl-color-gray-6); + } + + .copy-dropdown-item svg { + flex-shrink: 0; + margin-top: 0.125rem; + color: var(--sl-color-gray-3); + } + + .item-label { + font-weight: 500; + line-height: 1.4; + } + + .item-desc { + font-size: var(--sl-text-xs); + color: var(--sl-color-gray-3); + line-height: 1.4; + } + + .dropdown-divider { + height: 1px; + background: var(--sl-color-hairline-light); + margin: 0.25rem 0.625rem; + } + + /* Tooltip-style "Copied!" pill. The previous rule set only color + opacity + so the text floated transparently over the page H1 to its left. Mirror + the chrome from `.warp-kapa-button[data-tooltip]::after` in `kapa.css` + (Scalar control palette) so this reads as part of the same tooltip + system as the rest of the site. */ + .copy-toast { + position: absolute; + right: calc(100% + 0.5rem); + top: 50%; + transform: translateY(-50%); + padding: 0.375rem 0.5rem; + border: 1px solid var(--warp-control-border-hover, hsl(210, 5%, 30%)); + border-radius: var(--sl-radius-sm); + background: var(--warp-control-bg, #1a1a1a); + color: var(--sl-color-text-accent); + font-size: var(--sl-text-2xs); + font-family: var(--__sl-font, var(--sl-font)); + font-weight: 400; + line-height: 1.2; + white-space: nowrap; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25); + opacity: 0; + transition: opacity 0.2s ease; + pointer-events: none; + } + + :root[data-theme='light'] .copy-toast { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + } + + .copy-toast.visible { + opacity: 1; + } +</style> diff --git a/src/components/CustomHead.astro b/src/components/CustomHead.astro new file mode 100644 index 0000000..d039447 --- /dev/null +++ b/src/components/CustomHead.astro @@ -0,0 +1,50 @@ +--- +import Default from '@astrojs/starlight/components/Head.astro'; +import Analytics from '@vercel/analytics/astro'; +import SpeedInsights from '@vercel/speed-insights/astro'; +import RudderStackAnalytics from './RudderStackAnalytics.astro'; + +// Note: `<ClientRouter />` (Astro View Transitions) is intentionally NOT +// enabled here. Starlight's sidebar scroll persistence relies on the browser +// `pagehide` event to save `sessionStorage.sl-sidebar-state` and on inline +// `<script is:inline>` tags to restore it on the next full page load. With +// ClientRouter, navigations are client-side swaps: `pagehide` does not fire, +// inline scripts do not re-execute, and the sidebar pane is replaced with a +// fresh element whose `scrollTop` is 0 — the sidebar resets on every click. +// See SidebarPersistState.ts and SidebarPersister.astro in @astrojs/starlight. +// +// SEO meta tags (og:image, branded og:title, twitter:title/description/image, +// markdown alternate) are pushed into Starlight's head via the route +// middleware in src/routeData.ts so they go through Starlight's de-dup logic +// and override its bare defaults instead of producing duplicates. +const fontsHref = + 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap'; +--- + +<Default {...Astro.props}><slot /></Default> + +<!-- + Force the browser's native scroll restoration for back/forward navigation. + Defensive: some tools (and the previous `<ClientRouter />` we shipped) can + leave `history.scrollRestoration` stuck at `'manual'` in a tab's session, + which would make the main-window scroll jump to the top on back/forward. +--> +<script is:inline> + if ('scrollRestoration' in history) history.scrollRestoration = 'auto'; +</script> + +<!-- Google Fonts: preconnect, preload, then non-blocking stylesheet swap. --> +<link rel="preconnect" href="https://fonts.googleapis.com" /> +<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> +<link rel="preload" as="style" href={fontsHref} /> +<link + rel="stylesheet" + href={fontsHref} + media="print" + onload="this.media='all'" +/> +<RudderStackAnalytics /> +<noscript><link rel="stylesheet" href={fontsHref} /></noscript> + +<Analytics /> +<SpeedInsights /> diff --git a/src/components/CustomHeader.astro b/src/components/CustomHeader.astro new file mode 100644 index 0000000..59eac2e --- /dev/null +++ b/src/components/CustomHeader.astro @@ -0,0 +1,79 @@ +--- +// Custom Header override. +// +// Three-region layout: SiteTitle (left) | WarpTopicNav (middle) | +// SocialIcons + ThemeSelect + LanguageSelect (right). +// +// Search + Ask AI live inside the sidebar (Scalar pattern, see +// CustomSidebar.astro). The middle region carries the topic tabs (Terminal, +// Agents, Reference, etc.) as a horizontal nav (see WarpTopicNav.astro) — +// previously these lived in the sidebar but were moved up here for a more +// app-like top-level navigation. +// +// Default at: node_modules/@astrojs/starlight/components/Header.astro +import LanguageSelect from 'virtual:starlight/components/LanguageSelect'; +import SiteTitle from 'virtual:starlight/components/SiteTitle'; +import SocialIcons from 'virtual:starlight/components/SocialIcons'; +import ThemeSelect from 'virtual:starlight/components/ThemeSelect'; +import WarpTopicNav from './WarpTopicNav.astro'; +--- + +<div class="header"> + <div class="title-wrapper sl-flex"> + <SiteTitle /> + </div> + <div class="topic-nav-slot sl-hidden md:sl-flex print:hidden"> + <WarpTopicNav /> + </div> + <div class="sl-hidden md:sl-flex print:hidden right-group"> + <div class="sl-flex social-icons"> + <SocialIcons /> + </div> + <ThemeSelect /> + <LanguageSelect /> + </div> +</div> + +<style> + @layer starlight.core { + .header { + display: flex; + gap: var(--sl-nav-gap); + align-items: center; + height: 100%; + } + + .title-wrapper { + /* Prevent long titles overflowing and covering the menu button on + narrow viewports. */ + overflow: clip; + /* Avoid clipping focus ring around link inside title wrapper. */ + padding: 0.25rem; + margin: -0.25rem; + min-width: 0; + flex: none; + } + + /* Topic nav slot: takes all remaining width between SiteTitle and the + right group, vertically stretched so its child links can pin a + bottom-edge underline to the header hairline. */ + .topic-nav-slot { + flex: 1 1 auto; + align-self: stretch; + align-items: stretch; + min-width: 0; + } + + .right-group, + .social-icons { + gap: 1rem; + align-items: center; + flex: none; + } + .social-icons::after { + content: ''; + height: 2rem; + border-inline-end: 1px solid var(--sl-color-gray-5); + } + } +</style> diff --git a/src/components/CustomPageSidebar.astro b/src/components/CustomPageSidebar.astro new file mode 100644 index 0000000..d215fdd --- /dev/null +++ b/src/components/CustomPageSidebar.astro @@ -0,0 +1,139 @@ +--- +// Custom PageSidebar override. +// Adds a sticky footer to the "On this page" panel with edit link, +// community link, and last-updated timestamp. The footer pins to the +// bottom of the fixed-height right sidebar on desktop. +import MobileTableOfContents from 'virtual:starlight/components/MobileTableOfContents'; +import TableOfContents from 'virtual:starlight/components/TableOfContents'; + +const { editUrl, lastUpdated, lang } = Astro.locals.starlightRoute; +--- + +{ + Astro.locals.starlightRoute.toc && ( + <> + <div class="lg:sl-hidden"> + <MobileTableOfContents /> + </div> + <div class="right-sidebar-panel sl-hidden lg:sl-block"> + <div class="sl-container sidebar-col"> + <TableOfContents /> + <footer class="sidebar-footer"> + {editUrl && ( + <a href={editUrl} class="sidebar-footer__link"> + <svg aria-hidden="true" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg> + Edit page + </a> + )} + <a href="https://go.warp.dev/join-preview" class="sidebar-footer__link" target="_blank" rel="noopener noreferrer"> + <svg aria-hidden="true" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg> + Join our Slack community + </a> + {lastUpdated && ( + <p class="sidebar-footer__updated"> + Last updated{' '} + <time datetime={lastUpdated.toISOString()}> + {lastUpdated.toLocaleDateString(lang, { dateStyle: 'medium', timeZone: 'UTC' })} + </time> + </p> + )} + <p class="sidebar-footer__copyright">© {new Date().getFullYear()} Warp</p> + </footer> + </div> + </div> + </> + ) +} + +<style> + @layer starlight.core { + .right-sidebar-panel { + padding: 1rem var(--sl-sidebar-pad-x); + } + .sl-container { + width: calc(var(--sl-sidebar-width) - 2 * var(--sl-sidebar-pad-x)); + } + .right-sidebar-panel :global(h2) { + color: var(--sl-color-white); + font-size: var(--sl-text-h5); + font-weight: 600; + line-height: var(--sl-line-height-headings); + margin-bottom: 0.5rem; + } + .right-sidebar-panel :global(:where(a)) { + display: block; + font-size: var(--sl-text-xs); + text-decoration: none; + color: var(--sl-color-gray-3); + overflow-wrap: anywhere; + } + .right-sidebar-panel :global(:where(a):hover) { + color: var(--sl-color-white); + } + @media (min-width: 72rem) { + .sl-container { + max-width: calc( + ( + ( + 100vw - var(--sl-sidebar-width) - 2 * var(--sl-content-pad-x) - 2 * + var(--sl-sidebar-pad-x) + ) * 0.25 + ) + ); + } + } + + /* Make the container a flex column so the footer sticks to the bottom + of the fixed-height right sidebar. */ + .sidebar-col { + display: flex; + flex-direction: column; + height: calc(100vh - var(--sl-nav-height) - 2rem); + } + + /* Let the TOC scroll independently and fill available space */ + .sidebar-col > :global(starlight-toc) { + flex: 1; + overflow-y: auto; + scrollbar-width: none; + min-height: 0; + } + + /* Sticky footer pinned to the bottom of the sidebar */ + .sidebar-footer { + flex-shrink: 0; + padding-top: 0.75rem; + margin-top: 0.5rem; + border-top: 1px solid var(--sl-color-hairline-light); + display: flex; + flex-direction: column; + gap: 0.25rem; + } + + .sidebar-footer__link { + display: inline-flex !important; + align-items: center; + gap: 0.375rem; + font-size: var(--sl-text-xs) !important; + color: var(--sl-color-gray-3) !important; + text-decoration: none; + transition: color 0.15s ease; + } + + .sidebar-footer__link:hover { + color: var(--sl-color-white) !important; + } + + .sidebar-footer__link svg { + flex-shrink: 0; + opacity: 0.6; + } + + .sidebar-footer__updated, + .sidebar-footer__copyright { + font-size: var(--sl-text-2xs); + color: var(--sl-color-gray-4); + margin: 0; + } + } +</style> diff --git a/src/components/CustomPageTitle.astro b/src/components/CustomPageTitle.astro new file mode 100644 index 0000000..fc93fe1 --- /dev/null +++ b/src/components/CustomPageTitle.astro @@ -0,0 +1,57 @@ +--- +import CopyPageButton from './CopyPageButton.astro'; + +// Starlight types `entry.body` as `string | undefined`; fall back to '' +// so consumers (CopyPageButton) get a stable `string`. +const title = Astro.locals.starlightRoute.entry.data.title; +// Surface the page's `description` frontmatter as a visible subtitle below +// the H1. Starlight's default `PageTitle` only uses `description` for the +// `<meta name="description">` tag and OG/Twitter previews, so without this +// every page is missing the editorial lede that GitBook used to render. +// All 314 docs MDX files have a populated description today; the +// `&& <p>` guard keeps any future page that omits the field from emitting +// an empty paragraph. +const description = Astro.locals.starlightRoute.entry.data.description; +const body = Astro.locals.starlightRoute.entry.body ?? ''; +--- + +<div class="page-title-row"> + <h1 id="_top">{title}</h1> + <CopyPageButton body={body} title={title} /> +</div> +{description && <p class="page-subtitle">{description}</p>} + +<style> + .page-title-row { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 1rem; + } + + .page-title-row h1 { + flex: 1; + min-width: 0; + margin-top: 1rem; + font-size: var(--sl-text-h1); + line-height: var(--sl-line-height-headings); + font-weight: 700; + color: var(--sl-color-white); + } + + /* Editorial lede beneath the H1. Sized to body-prose scale so the lede + reads as a calm summary line a full step below the 32px H1 instead of + competing for emphasis. `gray-2` resolves to Oz `gray-300` / `gray-700` + (text-secondary) so contrast holds in both modes. `max-width: 42rem` + keeps the longest descriptions (≤262 chars across the corpus) wrapping + to a comfortable measure instead of stretching across the full column. */ + .page-subtitle { + margin-top: 0.5rem; + margin-bottom: 2rem; + max-width: 42rem; + font-size: var(--sl-text-body); + font-weight: 400; + line-height: 1.5; + color: var(--sl-color-gray-2); + } +</style> diff --git a/src/components/CustomSidebar.astro b/src/components/CustomSidebar.astro new file mode 100644 index 0000000..8ded00a --- /dev/null +++ b/src/components/CustomSidebar.astro @@ -0,0 +1,35 @@ +--- +// Custom Sidebar override. +// +// Scalar-style: search lives at the top of the sidebar, NOT in the top nav +// (see CustomHeader.astro for the matching header change). The Kapa "Ask" +// launcher sits beside the search pill on the same row, rendering as paired +// chrome via the shared `--warp-control-*` palette in `warp-components.css` +// §16. Below the row, the default Starlight sidebar nav renders with its +// items already filtered to the current topic (the +// `starlight-sidebar-topics` middleware rewrites `starlightRoute.sidebar` +// upstream). +// +// Topics themselves — Terminal, Agents, Reference, etc. — are rendered as +// horizontal links in the top header (see WarpTopicNav.astro). On narrow +// viewports (<50rem) the header collapses, so we still render the plugin's +// vertical topic list inside the mobile drawer via `md:sl-hidden` so users +// keep a way to switch topics. +// +// Reuses Starlight's built-in `<Search />` directly. The `<site-search>` +// custom element binds `⌘K` to `window`, so the trigger button can live +// anywhere in the DOM and the dialog (portaled to `<body>`) keeps working. +import Default from '@astrojs/starlight/components/Sidebar.astro'; +import Search from '@astrojs/starlight/components/Search.astro'; +import StarlightSidebarTopicsSidebar from 'starlight-sidebar-topics/components/Sidebar.astro'; +import KapaLauncher from './KapaLauncher.astro'; +--- + +<div class="warp-sidebar-search"> + <Search /> + <KapaLauncher /> +</div> +<div class="md:sl-hidden"> + <StarlightSidebarTopicsSidebar /> +</div> +<Default><slot /></Default> diff --git a/src/components/CustomSiteTitle.astro b/src/components/CustomSiteTitle.astro new file mode 100644 index 0000000..2d63138 --- /dev/null +++ b/src/components/CustomSiteTitle.astro @@ -0,0 +1,82 @@ +--- +// Custom SiteTitle override. +// +// Why this exists: +// Starlight's default SiteTitle (`@astrojs/starlight/components/SiteTitle.astro`) +// renders the logo as two `<img>` tags pointing at hashed SVG files (one for +// light theme, one for dark). Because we have View Transitions disabled in +// `CustomHead.astro` (so Starlight's sidebar scroll persistence keeps +// working), every internal link is a full document navigation: the header is +// torn down and rebuilt on each click. With `<img>`-based SVGs, the surrounding +// header background paints a frame or two before the image decodes, which +// reads as a flicker on every nav. +// +// This override inlines both SVGs directly into the HTML via Vite's `?raw` +// import, so the logo paints in the same frame as the rest of the header. We +// keep Starlight's `light:sl-hidden` / `dark:sl-hidden` toggle classes so the +// light/dark switch keeps working with zero JS, and we keep the sr-only site +// title for accessibility. +import config from 'virtual:starlight/user-config'; +import logoDark from '../assets/warp-logo-dark.svg?raw'; +import logoLight from '../assets/warp-logo-light.svg?raw'; + +// We deliberately ignore Starlight's `siteTitleHref` (which defaults to `/`) +// and point the brand wordmark at warp.dev instead. Convention across the +// product family: the logo is the marketing-site jump; navigation back to +// docs home lives in the sidebar topic nav. +const { siteTitle } = Astro.locals.starlightRoute; +--- + +<a href="https://warp.dev" class="site-title sl-flex"> + <span + class="logo light:sl-hidden print:hidden" + aria-hidden="true" + set:html={logoDark} + /> + <span + class="logo dark:sl-hidden print:block" + aria-hidden="true" + set:html={logoLight} + /> + <span class:list={{ 'sr-only': config.logo?.replacesTitle }} translate="no"> + {siteTitle} + </span> +</a> + +<style> + /* Match Starlight's default SiteTitle layout/sizing exactly so the visual + result is unchanged. */ + .site-title { + align-items: center; + gap: var(--sl-nav-gap); + font-size: var(--sl-text-h4); + font-weight: 600; + color: var(--sl-color-text-accent); + text-decoration: none; + white-space: nowrap; + min-width: 0; + } + + .logo { + /* Use inline-flex so the inlined <svg> child is laid out like an <img> + would be (no extra baseline gap, no shrink). + The light:/dark: sl-hidden utilities (in @layer starlight.utils) set + display:none to toggle logos. Our unlayered display:inline-flex would + override that, showing both logos at once. Scope it inside the same + layer so the hidden utility wins when it applies. */ + flex-shrink: 0; + } + @layer starlight.utils { + .logo { + display: inline-flex; + align-items: center; + } + } + + .logo :global(svg) { + height: 1.25rem; + width: auto; + max-width: 100%; + display: block; + } +</style> diff --git a/src/components/DemoVideo.astro b/src/components/DemoVideo.astro new file mode 100644 index 0000000..b1bb6f1 --- /dev/null +++ b/src/components/DemoVideo.astro @@ -0,0 +1,36 @@ +--- +/** + * Renders the canonical autoplay demo video used throughout the docs. + * + * Each demo video has a matching JPEG poster in `public/assets/...` named + * `<basename>.poster.jpg` (generated by ffmpeg from the first frame). The + * component derives the poster URL automatically so callers only need to + * pass `src` and a descriptive `label`. + * + * Use `preload="none"` so off-screen videos don't consume bandwidth on + * page load. Browsers will still fetch and start playback once the + * `<video>` element scrolls into view (the `autoplay` + `playsinline` + * combo is honoured on both desktop and mobile when the video is muted). + */ +interface Props { + src: string; + label: string; + poster?: string; + width?: string; +} + +const { src, label, poster, width = '100%' } = Astro.props; +const resolvedPoster = poster ?? src.replace(/\.mp4$/, '.poster.jpg'); +--- +<video + autoplay + muted + loop + playsinline + width={width} + aria-label={label} + poster={resolvedPoster} + preload="none" +> + <source src={src} type="video/mp4" /> +</video> diff --git a/src/components/FeedbackButtons.astro b/src/components/FeedbackButtons.astro new file mode 100644 index 0000000..326a5f3 --- /dev/null +++ b/src/components/FeedbackButtons.astro @@ -0,0 +1,162 @@ +--- +/** + * Shared PushFeedback thumbs-up/down widget. + * + * Used by: + * - `FeedbackFooter.astro` — appears at the bottom of every Starlight page + * - `pages/api.astro` — fixed bottom-right on the standalone /api page + * + * Both call sites previously hand-rolled the same markup (identical SVG + * paths, identical `<feedback-button>` props). This consolidates them so + * future changes (icons, label, modal-position) land in one place. + * + * The PushFeedback CDN assets used to ship in the page `<head>` (via + * `astro.config.mjs` for Starlight pages and inline for `/api`), which + * meant a render-blocking CSS round-trip + a deferred 70 KB+ script on + * every page even though the widget only renders below the fold. The + * inline `<script is:inline>` below now injects the CSS link + script tag + * inside `requestIdleCallback` (or after a short timeout in browsers + * without it), keeping the assets off the critical path. The custom + * element upgrades any already-rendered `<feedback-button>` elements as + * soon as the script registers it, so there's no flash. + * + * If `PUBLIC_PUSHFEEDBACK_PROJECT_ID` is unset, this component renders + * nothing — including the loader — so the assets are never fetched. + * + * The `<feedback-button>` custom element doesn't have type definitions, so + * we render the markup as plain HTML. + */ +const PROJECT_ID = import.meta.env.PUBLIC_PUSHFEEDBACK_PROJECT_ID; + +interface Props { + /** Question text shown next to the buttons. */ + question?: string; + /** Class on the wrapping element so callers can style placement/layout. */ + class?: string; + /** Class on the question label. */ + questionClass?: string; + /** Class on each thumbs button. */ + buttonClass?: string; + /** Optional `page` attribute passed to PushFeedback (defaults to current path on the dashboard). */ + page?: string; +} + +const { + question = 'Was this page helpful?', + class: wrapperClass = 'feedback-widget', + questionClass = 'feedback-question', + buttonClass = 'feedback-btn', + page, +} = Astro.props; +--- + +{PROJECT_ID && ( + <> + {/* Lazy loader for the PushFeedback CDN assets. A global flag + (`window.__warpFeedbackLoaderQueued`) makes this idempotent across + repeated `<FeedbackButtons />` instances on the same page. The CSS + and module script are injected during browser idle time so they + don't block first paint; the custom element upgrades any + already-rendered `<feedback-button>` markup as soon as it registers. */} + <script is:inline> + (function () { + if (typeof window === 'undefined') return; + if (window.__warpFeedbackLoaderQueued) return; + window.__warpFeedbackLoaderQueued = true; + var load = function () { + var link = document.createElement('link'); + link.rel = 'stylesheet'; + link.href = 'https://cdn.jsdelivr.net/npm/pushfeedback@0.1.82/dist/pushfeedback/pushfeedback.css'; + link.integrity = 'sha384-ApUY3yzqjkYETPrUq54/6LgjrJqExWoRtdaan/l1GlXu9WMcmlamohmmMuOcHpJY'; + link.crossOrigin = 'anonymous'; + document.head.appendChild(link); + var script = document.createElement('script'); + script.type = 'module'; + script.src = 'https://cdn.jsdelivr.net/npm/pushfeedback@0.1.82/dist/pushfeedback/pushfeedback.esm.js'; + script.integrity = 'sha384-V+NyTgfUiXpY70lXORDYoLb1JOe5bOw4XiN513kc8gD60ksOD7JvXpaSCqCCV6e+'; + script.crossOrigin = 'anonymous'; + document.head.appendChild(script); + }; + if (typeof window.requestIdleCallback === 'function') { + window.requestIdleCallback(load, { timeout: 3000 }); + } else { + // Safari (≤16.3) fallback — load shortly after first paint. + setTimeout(load, 1500); + } + })(); + </script> + <div class={wrapperClass}> + <span class={questionClass}>{question}</span> + <feedback-button + project={PROJECT_ID} + rating="1" + page={page} + modal-position="center" + button-style="default" + class={buttonClass} + > + <svg aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> + <path d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3" /> + </svg> + Yes + </feedback-button> + <feedback-button + project={PROJECT_ID} + rating="0" + page={page} + modal-position="center" + button-style="default" + class={buttonClass} + > + <svg aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> + <path d="M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17" /> + </svg> + No + </feedback-button> + </div> + </> +)} + +<style is:global> + /* Default styling for the Starlight-footer placement (matches the prior + scoped rules in FeedbackFooter.astro). Marked `is:global` so callers + can also pass their own class names without re-declaring these rules. + `api.astro` overrides via the `class`/`questionClass`/`buttonClass` + props and ships its own styles. */ + .feedback-widget { + display: flex; + align-items: center; + gap: 0.5rem; + } + + .feedback-question { + color: var(--sl-color-gray-3); + font-size: var(--sl-text-sm); + margin: 0; + } + + .feedback-btn { + display: inline-flex; + align-items: center; + gap: 0.3rem; + padding: 0.25rem 0.6rem; + border: none; + border-radius: var(--sl-radius-md); + background: transparent; + color: var(--sl-color-gray-3); + font-size: var(--sl-text-xs); + font-family: var(--sl-font); + cursor: pointer; + transition: color 0.15s ease, background-color 0.15s ease; + } + + .feedback-btn:hover { + color: var(--sl-color-white); + background: var(--sl-color-gray-5); + } + + .feedback-btn svg { + width: 14px; + height: 14px; + } +</style> diff --git a/src/components/FeedbackFooter.astro b/src/components/FeedbackFooter.astro new file mode 100644 index 0000000..c6ae987 --- /dev/null +++ b/src/components/FeedbackFooter.astro @@ -0,0 +1,47 @@ +--- +// Custom footer with PushFeedback "Was this helpful?" widget. +// PushFeedback CDN is loaded via Starlight's `head` config in astro.config.mjs. +// Dashboard: https://app.pushfeedback.com +import Pagination from 'virtual:starlight/components/Pagination'; +import config from 'virtual:starlight/user-config'; +import FeedbackButtons from './FeedbackButtons.astro'; +--- + +<footer class="sl-flex"> + <FeedbackButtons /> + + <Pagination /> + + { + config.credits && ( + <a class="kudos sl-flex" href="https://starlight.astro.build"> + {Astro.locals.t('builtWithStarlight.label')} + </a> + ) + } +</footer> + +<style> + /* `.feedback-*` rules live alongside the markup in FeedbackButtons.astro + so they ship together. Only footer-level layout stays here. */ + @layer starlight.core { + footer { + flex-direction: column; + gap: 1.25rem; + margin-top: 2rem; + padding-top: 1.25rem; + border-top: 1px solid var(--sl-color-hairline-light); + } + .kudos { + align-items: center; + gap: 0.5em; + margin: 1.5rem auto; + font-size: var(--sl-text-xs); + text-decoration: none; + color: var(--sl-color-gray-3); + } + .kudos:hover { + color: var(--sl-color-white); + } + } +</style> diff --git a/src/components/ImageGrid.astro b/src/components/ImageGrid.astro new file mode 100644 index 0000000..a10d7d2 --- /dev/null +++ b/src/components/ImageGrid.astro @@ -0,0 +1,32 @@ +--- +/** + * Renders a responsive grid of image cards with labels. + * + * Designed to replace GitBook's `<table data-view="cards">` layout for + * visual showcase grids (e.g. app icons, theme previews). + * + * Usage: + * <ImageGrid> + * <ImageGridItem src="..." label="Name" /> + * ... + * </ImageGrid> + */ +--- + +<div class="image-grid"><slot /></div> + +<style> + .image-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); + gap: 1.5rem; + margin-top: 1rem; + } + + @media (max-width: 30rem) { + .image-grid { + grid-template-columns: repeat(2, 1fr); + gap: 1rem; + } + } +</style> diff --git a/src/components/ImageGridItem.astro b/src/components/ImageGridItem.astro new file mode 100644 index 0000000..e536ee5 --- /dev/null +++ b/src/components/ImageGridItem.astro @@ -0,0 +1,50 @@ +--- +/** + * A single image + label card for use inside <ImageGrid>. + * + * Props: + * src – path to the image (relative import or public path) + * label – display name shown below the image + * alt – optional alt text (defaults to "{label} preview") + */ +import type { ImageMetadata } from 'astro'; + +interface Props { + src: ImageMetadata; + label: string; + alt?: string; +} + +const { src, label, alt } = Astro.props; +--- + +<figure class="image-grid-item"> + <img src={src.src} alt={alt ?? `${label} preview`} loading="lazy" decoding="async" width={src.width} height={src.height} /> + <figcaption>{label}</figcaption> +</figure> + +<style> + .image-grid-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5rem; + margin: 0; + padding: 0; + } + + .image-grid-item img { + width: 100%; + height: auto; + border-radius: var(--sl-radius-lg, 0.5rem); + border: 1px solid var(--sl-color-gray-5, #e5e7eb); + object-fit: cover; + } + + .image-grid-item figcaption { + font-size: var(--sl-text-sm, 0.875rem); + color: var(--sl-color-gray-2, #6b7280); + text-align: center; + line-height: 1.4; + } +</style> diff --git a/src/components/KapaChatLauncher.css b/src/components/KapaChatLauncher.css new file mode 100644 index 0000000..724b457 --- /dev/null +++ b/src/components/KapaChatLauncher.css @@ -0,0 +1,450 @@ +.warp-kapa-shell { + display: contents; +} + +.sl-kapa-dialog { + position: fixed; + inset: 0; + width: 100%; + height: 100%; + max-width: none; + max-height: none; + margin: 0; + padding: 0; + border: 0; + background: transparent; + overflow: hidden; +} + +.sl-kapa-dialog::backdrop { + background: rgb(18 18 18 / 0.55); + backdrop-filter: blur(2px); +} + +.sl-kapa-panel { + margin-left: auto; + display: flex; + flex-direction: column; + width: min(28rem, 100vw); + height: 100%; + background: var(--sl-color-black); + border-left: 1px solid var(--sl-color-gray-5); + box-shadow: var(--sl-shadow-xl); +} + + +.sl-kapa-panel__header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.5rem 1rem; + background: transparent; + border: 0; +} + +.sl-kapa-panel__header-actions { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.sl-kapa-icon-button, +.sl-kapa-feedback__button { + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + width: 2.25rem; + height: 2.25rem; + border: 1px solid var(--warp-control-border); + border-radius: var(--sl-radius-sm); + background: var(--warp-control-bg); + color: var(--warp-control-icon); + cursor: pointer; + transition: + border-color 0.15s ease, + color 0.15s ease, + background-color 0.15s ease; +} +.sl-kapa-icon-button svg, +.sl-kapa-feedback__button svg, +.sl-kapa-submit svg { + width: 1rem; + height: 1rem; + flex: none; +} + +.sl-kapa-icon-button--close { + width: 2rem; + height: 2rem; +} + +.sl-kapa-icon-button--ghost { + border-color: transparent; + background: transparent; +} + +.sl-kapa-icon-button:disabled, +.sl-kapa-feedback__button:disabled { + cursor: not-allowed; + opacity: 0.5; +} +.sl-kapa-icon-button[data-tooltip]::after { + content: attr(data-tooltip); + position: absolute; + top: calc(100% + 0.5rem); + left: 0; + padding: 0.375rem 0.5rem; + border: 1px solid var(--warp-control-border-hover); + border-radius: var(--sl-radius-sm); + background: var(--warp-control-bg); + color: var(--warp-control-text-hover); + font-family: var(--__sl-font, 'Inter', sans-serif); + font-size: var(--sl-text-2xs); + font-weight: 400; + line-height: 1.2; + white-space: nowrap; + pointer-events: none; + opacity: 0; + transform: translateY(-2px); + transition: + opacity 0.15s ease, + transform 0.15s ease; + transition-delay: 0.35s; + z-index: 10; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25); +} + +.sl-kapa-icon-button[data-tooltip]:hover::after, +.sl-kapa-icon-button[data-tooltip]:focus-visible::after { + opacity: 1; + transform: translateY(0); +} + +.sl-kapa-icon-button:hover:not(:disabled), +.sl-kapa-feedback__button:hover:not(:disabled) { + border-color: var(--warp-control-border-hover); + background: var(--warp-control-bg-hover); + color: var(--warp-control-text-hover); +} + +.sl-kapa-icon-button:focus-visible, +.sl-kapa-feedback__button:focus-visible { + outline: 2px solid var(--sl-color-accent-high); + outline-offset: 2px; +} + +.sl-kapa-panel__body { + flex: 1 1 auto; + overflow-y: auto; + padding: 1rem; + display: flex; + flex-direction: column; + gap: 1rem; +} + +.sl-kapa-empty-state { + margin: auto 0; + padding: 1rem; + border: 1px dashed var(--sl-color-gray-5); + border-radius: var(--sl-radius-lg); + color: var(--sl-color-gray-2); +} + +.sl-kapa-empty-state__title { + margin: 0 0 0.375rem; + font-weight: 600; + color: var(--sl-color-white); +} + +.sl-kapa-message-group { + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.sl-kapa-message { + border-radius: var(--sl-radius-lg); + padding: 0.875rem 1rem; + line-height: 1.6; + font-size: var(--sl-text-sm); +} + +.sl-kapa-message--user { + align-self: flex-end; + max-width: 88%; + background: var(--sl-color-text-accent); + color: var(--sl-color-black); +} + +.sl-kapa-message--assistant { + align-self: flex-start; + width: 100%; + background: color-mix(in srgb, var(--sl-color-black), var(--sl-color-gray-6) 28%); + border: 1px solid var(--sl-color-gray-5); + color: var(--sl-color-gray-1); +} + +.sl-kapa-message--assistant :first-child { + margin-top: 0; +} + +.sl-kapa-message--assistant :last-child { + margin-bottom: 0; +} + +.sl-kapa-message--assistant p code, +.sl-kapa-message--assistant li code { + background: var(--sl-color-gray-6); + border-radius: var(--sl-radius-sm); + padding: 0.1rem 0.3rem; +} + +.sl-kapa-thinking { + display: flex; + align-items: center; + gap: 0.5rem; + color: var(--sl-color-gray-2); +} + +.sl-kapa-spinner { + animation: sl-kapa-spin 1s linear infinite; +} + +.sl-kapa-sources { + margin-top: 1rem; + padding-top: 0.75rem; + border-top: 1px solid var(--sl-color-gray-5); +} + +.sl-kapa-sources p { + margin: 0 0 0.5rem; + font-size: var(--sl-text-xs); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--sl-color-gray-3); +} + +.sl-kapa-sources ul { + list-style: none; + padding: 0; + margin: 0; + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.sl-kapa-sources a { + display: inline-flex; + align-items: center; + gap: 0.35rem; + color: var(--sl-color-text-accent); + text-decoration: none; +} + +.sl-kapa-sources a:hover { + text-decoration: underline; +} + +.sl-kapa-feedback { + display: flex; + gap: 0.5rem; + margin-top: 0.875rem; +} + +.sl-kapa-error { + border: 1px solid color-mix(in srgb, #ef4444, var(--sl-color-black) 35%); + background: rgb(127 29 29 / 0.2); + color: #fecaca; + border-radius: var(--sl-radius-lg); + padding: 0.875rem 1rem; +} + +.sl-kapa-panel__footer { + position: relative; + padding: 1rem; + background: color-mix(in srgb, var(--sl-color-black), var(--sl-color-gray-6) 35%); + border-top: 1px solid var(--sl-color-gray-5); +} + +.sl-kapa-form { + display: flex; + gap: 0.75rem; +} + +.sl-kapa-form input { + flex: 1 1 auto; + min-width: 0; + height: 2.75rem; + border: 1px solid var(--sl-color-gray-5); + border-radius: var(--sl-radius-md); + background: var(--sl-color-black); + color: var(--sl-color-white); + padding: 0 0.875rem; + font: inherit; +} + +.sl-kapa-form input::placeholder { + color: var(--sl-color-gray-3); +} + +.sl-kapa-form input:focus-visible { + outline: 2px solid var(--sl-color-accent-high); + outline-offset: 2px; +} + +.sl-kapa-submit { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + width: 2.75rem; + height: 2.75rem; + padding: 0; + border: 1px solid var(--sl-color-text-accent); + border-radius: var(--sl-radius-md); + background: var(--sl-color-text-accent); + color: var(--sl-color-black); + font: inherit; + font-weight: 600; + cursor: pointer; + transition: + border-color 0.15s ease, + background-color 0.15s ease, + transform 0.15s ease; +} + +.sl-kapa-submit:hover:not(:disabled) { + border-color: color-mix(in srgb, var(--sl-color-text-accent), var(--sl-color-white) 18%); + background: color-mix(in srgb, var(--sl-color-text-accent), var(--sl-color-white) 8%); +} + +.sl-kapa-submit:focus-visible { + outline: 2px solid var(--sl-color-accent-high); + outline-offset: 2px; +} + +.sl-kapa-submit:active:not(:disabled) { + transform: translateY(1px); +} + +.sl-kapa-submit:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +/* Hide the reCAPTCHA badge */ +.grecaptcha-badge { + visibility: hidden; +} +.sl-kapa-meta { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + margin-top: 0.75rem; + font-size: var(--sl-text-xs); + color: var(--sl-color-gray-3); +} + +.sl-kapa-attribution, +.sl-kapa-disclosure { + margin: 0; + line-height: 1.4; +} +.sl-kapa-disclosure-trigger { + border: 0; + padding: 0; + background: transparent; + color: inherit; + font: inherit; + text-decoration: underline; + text-underline-offset: 0.12em; + cursor: pointer; +} + +.sl-kapa-disclosure-trigger:hover, +.sl-kapa-disclosure-trigger:focus-visible { + color: var(--sl-color-gray-1); +} + +.sl-kapa-disclosure-trigger:focus-visible { + outline: 2px solid var(--sl-color-accent-high); + outline-offset: 3px; + border-radius: var(--sl-radius-xs); +} + +.sl-kapa-attribution a, + +.sl-kapa-disclosure a { + color: inherit; +} + +.sl-kapa-popover { + max-width: min(22rem, calc(100vw - 2rem)); + border: 1px solid var(--sl-color-gray-5); + border-radius: var(--sl-radius-lg); + background: color-mix(in srgb, var(--sl-color-black), var(--sl-color-gray-6) 18%); + box-shadow: var(--sl-shadow-lg); + padding: 0.75rem 0.875rem; + font-size: var(--sl-text-xs); + line-height: 1.5; + color: var(--sl-color-gray-2); + z-index: 10; +} + +.sl-kapa-popover p { + margin: 0; +} + +.sl-kapa-popover a { + color: var(--sl-color-text-accent); +} + +.sl-kapa-popover__arrow { + fill: color-mix(in srgb, var(--sl-color-black), var(--sl-color-gray-6) 18%); +} + +@keyframes sl-kapa-popover-in { + from { + opacity: 0; + transform: translateY(4px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +.sl-kapa-popover[data-state='open'] { + animation: sl-kapa-popover-in 120ms ease-out; +} + +@media (max-width: 36rem) { + .sl-kapa-meta { + flex-direction: column; + align-items: flex-start; + } +} + +@keyframes sl-kapa-spin { + from { + transform: rotate(0deg); + } + + to { + transform: rotate(360deg); + } +} + +@media (max-width: 50rem) { + .sl-kapa-panel { + width: 100vw; + } + + .sl-kapa-message--user { + max-width: 100%; + } +} diff --git a/src/components/KapaChatLauncher.mount.tsx b/src/components/KapaChatLauncher.mount.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/KapaChatLauncher.tsx b/src/components/KapaChatLauncher.tsx new file mode 100644 index 0000000..6d218ad --- /dev/null +++ b/src/components/KapaChatLauncher.tsx @@ -0,0 +1,358 @@ +import type { FormEvent, MouseEvent } from 'react'; +import * as Popover from '@radix-ui/react-popover'; +import { useEffect, useMemo, useRef, useState } from 'react'; +import { KapaProvider, useChat } from '@kapaai/react-sdk'; +import { PUBLIC_KAPA_INTEGRATION_ID } from 'astro:env/client'; +import { isMac, keymatch } from 'keymatch'; +import ReactMarkdown from 'react-markdown'; +import { + LuExternalLink, + LuLoaderCircle, + LuMessageSquare, + LuSend, + LuSquarePen, + LuThumbsDown, + LuThumbsUp, + LuX, +} from 'react-icons/lu'; +import './KapaChatLauncher.css'; + +const integrationId = PUBLIC_KAPA_INTEGRATION_ID; +const title = 'Ask Warp'; +const welcomeMessage = 'What do you want to know about Warp?'; + +type FeedbackReaction = 'upvote' | 'downvote'; + +function ChatSurface({ title, welcomeMessage, autoOpen = false, onNewConversation }: { + title: string; + welcomeMessage: string; + autoOpen?: boolean; + onNewConversation: () => void; +}) { + const [isOpen, setIsOpen] = useState(autoOpen); + const [query, setQuery] = useState(''); + const [hasStartedConversation, setHasStartedConversation] = useState(false); + const [isAppleDevice, setIsAppleDevice] = useState(false); + const messagesRef = useRef<HTMLDivElement | null>(null); + const dialogRef = useRef<HTMLDialogElement | null>(null); + const triggerRef = useRef<HTMLButtonElement | null>(null); + const closeButtonRef = useRef<HTMLButtonElement | null>(null); + const inputRef = useRef<HTMLInputElement | null>(null); + const { + addFeedback, + conversation, + error, + isGeneratingAnswer, + isPreparingAnswer, + submitQuery, + } = useChat(); + useEffect(() => { + setIsAppleDevice(isMac()); + }, []); + + useEffect(() => { + if (!isOpen || !messagesRef.current) return; + messagesRef.current.scrollTop = messagesRef.current.scrollHeight; + }, [conversation.length, isOpen]); + + useEffect(() => { + const dialog = dialogRef.current; + if (!dialog) return; + + if (isOpen) { + if (!dialog.open) { + dialog.showModal(); + } + + const frame = window.requestAnimationFrame(() => { + if (inputRef.current && !inputRef.current.disabled) { + inputRef.current.focus(); + return; + } + + closeButtonRef.current?.focus(); + }); + + return () => { + window.cancelAnimationFrame(frame); + }; + } + + if (dialog.open) { + dialog.close(); + } + }, [isOpen]); + + useEffect(() => { + const onKeyDown = (event: KeyboardEvent) => { + if (keymatch(event, 'CmdOrCtrl+I')) { + if (dialogRef.current?.open) { + closePanel(); + } else { + openPanel(); + } + event.preventDefault(); + } + }; + + window.addEventListener('keydown', onKeyDown); + return () => { + window.removeEventListener('keydown', onKeyDown); + }; + }, []); + + const hasConversation = conversation.length > 0; + const isBusy = isGeneratingAnswer || isPreparingAnswer; + + const submit = () => { + const value = query.trim(); + if (!value || isBusy) return; + submitQuery(value); + setHasStartedConversation(true); + setQuery(''); + }; + + const onSubmit = (event: FormEvent<HTMLFormElement>) => { + event.preventDefault(); + submit(); + }; + + const feedback = (questionAnswerId: string, reaction: FeedbackReaction) => { + addFeedback(questionAnswerId, reaction); + }; + + const openPanel = () => { + setIsOpen(true); + }; + + const closePanel = () => { + dialogRef.current?.close(); + }; + + const restoreFocus = () => { + window.requestAnimationFrame(() => { + triggerRef.current?.focus(); + }); + }; + + const onDialogClose = () => { + setIsOpen(false); + restoreFocus(); + }; + + const onDialogClick = (event: MouseEvent<HTMLDialogElement>) => { + if (event.target === dialogRef.current) { + closePanel(); + } + }; + + return ( + <div className="warp-kapa-shell"> + <button + type="button" + ref={triggerRef} + className="warp-kapa-button" + onClick={openPanel} + aria-label="Ask Kapa AI" + aria-haspopup="dialog" + aria-expanded={isOpen} + aria-controls="sl-kapa-panel" + aria-keyshortcuts={isAppleDevice ? 'Meta+I' : 'Control+I'} + data-tooltip={isAppleDevice ? 'Ask Kapa AI ⌘I' : 'Ask Kapa AI Ctrl+I'} + > + <LuMessageSquare aria-hidden="true" /> + <span className="warp-kapa-button__label">Ask</span> + </button> + <dialog + ref={dialogRef} + id="sl-kapa-panel" + className="sl-kapa-dialog" + aria-label={title} + onClose={onDialogClose} + onClick={onDialogClick} + > + <div className="sl-kapa-panel"> + <header className="sl-kapa-panel__header"> + <button + type="button" + className="sl-kapa-icon-button sl-kapa-icon-button--ghost" + onClick={onNewConversation} + disabled={!hasStartedConversation} + aria-label="New conversation" + data-tooltip="New conversation" + > + <LuSquarePen aria-hidden="true" /> + </button> + <div className="sl-kapa-panel__header-actions"> + <button + type="button" + ref={closeButtonRef} + className="sl-kapa-icon-button sl-kapa-icon-button--close sl-kapa-icon-button--ghost" + onClick={closePanel} + aria-label="Close AI chat" + > + <LuX aria-hidden="true" /> + </button> + </div> + </header> + + <div className="sl-kapa-panel__body" ref={messagesRef}> + {!hasConversation && ( + <div className="sl-kapa-empty-state"> + <p className="sl-kapa-empty-state__title">Ask a question</p> + <p>{welcomeMessage}</p> + </div> + )} + + {conversation.map((qa) => ( + <div className="sl-kapa-message-group" key={qa.id ?? `temp-${qa.question}`}> + <div className="sl-kapa-message sl-kapa-message--user">{qa.question}</div> + <div className="sl-kapa-message sl-kapa-message--assistant"> + {qa.answer ? ( + <ReactMarkdown>{qa.answer}</ReactMarkdown> + ) : ( + <div className="sl-kapa-thinking"> + <LuLoaderCircle className="sl-kapa-spinner" aria-hidden="true" /> + <span>{isPreparingAnswer ? 'Preparing answer…' : 'Generating answer…'}</span> + </div> + )} + + {qa.sources?.length ? ( + <div className="sl-kapa-sources"> + <p>Sources</p> + <ul> + {qa.sources.map((source, index) => ( + <li key={`${source.source_url}-${index}`}> + <a href={source.source_url} target="_blank" rel="noreferrer"> + <span>{source.title}</span> + <LuExternalLink aria-hidden="true" /> + </a> + </li> + ))} + </ul> + </div> + ) : null} + + {qa.id ? ( + <div className="sl-kapa-feedback"> + <button + type="button" + className="sl-kapa-feedback__button" + onClick={() => feedback(qa.id as string, 'upvote')} + aria-label="Mark answer as helpful" + > + <LuThumbsUp aria-hidden="true" /> + </button> + <button + type="button" + className="sl-kapa-feedback__button" + onClick={() => feedback(qa.id as string, 'downvote')} + aria-label="Mark answer as not helpful" + > + <LuThumbsDown aria-hidden="true" /> + </button> + </div> + ) : null} + </div> + </div> + ))} + + {error ? <div className="sl-kapa-error">{error}</div> : null} + </div> + <footer className="sl-kapa-panel__footer"> + <form className="sl-kapa-form" onSubmit={onSubmit}> + <input + ref={inputRef} + type="text" + value={query} + onChange={(event) => setQuery(event.target.value)} + placeholder="Ask a question about Warp…" + /> + <button + type="submit" + className="sl-kapa-submit" + disabled={isBusy || !query.trim()} + aria-label="Send message" + > + <LuSend aria-hidden="true" /> + </button> + </form> + <div className="sl-kapa-meta"> + <p className="sl-kapa-attribution"> + Powered by{' '} + <a href="https://kapa.ai" target="_blank" rel="noreferrer"> + kapa.ai + </a> + </p> + <Popover.Root> + <p className="sl-kapa-disclosure"> + Protected by{' '} + <Popover.Trigger asChild> + <button type="button" className="sl-kapa-disclosure-trigger"> + reCAPTCHA + </button> + </Popover.Trigger> + </p> + <Popover.Content + className="sl-kapa-popover" + side="top" + align="end" + sideOffset={8} + > + <p> + This site is protected by reCAPTCHA and the Google{' '} + <a href="https://policies.google.com/privacy" target="_blank" rel="noreferrer"> + Privacy Policy + </a>{' '} + and{' '} + <a href="https://policies.google.com/terms" target="_blank" rel="noreferrer"> + Terms of Service + </a>{' '} + apply. + </p> + <Popover.Arrow className="sl-kapa-popover__arrow" /> + </Popover.Content> + </Popover.Root> + </div> + </footer> + </div> + </dialog> + </div> + ); +} + +export default function KapaChatLauncher({ autoOpen = false }: { autoOpen?: boolean } = {}) { + const [chatSessionKey, setChatSessionKey] = useState(0); + const [sessionAutoOpen, setSessionAutoOpen] = useState(autoOpen); + const callbacks = useMemo( + () => ({ + askAI: {}, + }), + [] + ); + if (!integrationId) { + return null; + } + const startNewConversation = () => { + // `autoOpen` is read once by each keyed `ChatSurface` remount so the + // fresh conversation opens immediately without controlling later renders. + setSessionAutoOpen(true); + setChatSessionKey((key) => key + 1); + }; + + return ( + <KapaProvider + key={chatSessionKey} + integrationId={integrationId} + callbacks={callbacks} + userTrackingMode="none" + > + <ChatSurface + title={title} + welcomeMessage={welcomeMessage} + autoOpen={sessionAutoOpen} + onNewConversation={startNewConversation} + /> + </KapaProvider> + ); +} diff --git a/src/components/KapaLauncher.astro b/src/components/KapaLauncher.astro new file mode 100644 index 0000000..028bc96 --- /dev/null +++ b/src/components/KapaLauncher.astro @@ -0,0 +1,8 @@ +--- +// The button sits to the right of the sidebar search pill (see +// CustomSidebar.astro), rendering as `[icon] Ask` at one type-scale step +// smaller than search so it reads as the secondary affordance. +import KapaChatLauncher from './KapaChatLauncher'; +--- + +<KapaChatLauncher client:idle /> diff --git a/src/components/RudderStackAnalytics.astro b/src/components/RudderStackAnalytics.astro new file mode 100644 index 0000000..37a8a67 --- /dev/null +++ b/src/components/RudderStackAnalytics.astro @@ -0,0 +1,103 @@ +--- +/** + * RudderStack analytics — CDN inline snippet. + * + * Uses `set:html` to output the official RudderStack v3 async stub with + * credentials substituted at server render time. This bypasses Vite's module + * graph while still keeping the no-keys-no-script behavior. + * + * Notes: + * - The snippet version is RudderStack JS SDK v3.2.0. + * - `polyfill-fastly.io` is intentionally allowlisted instead of the now- + * compromised `cdn.polyfill.io` host. + */ +const writeKey = import.meta.env.PUBLIC_RUDDERSTACK_WRITE_KEY; +const dataplaneUrl = import.meta.env.PUBLIC_RUDDERSTACK_DATA_PLANE_URL; +const enabled = !!(writeKey && dataplaneUrl); + +const writeKeyJs = JSON.stringify(writeKey ?? ''); +const dataplaneUrlJs = JSON.stringify(dataplaneUrl ?? ''); + +const scriptBody = enabled + ? [ + '// RudderStack JS SDK v3.2.0 async stub.', + '!function(){', + ' "use strict";', + ' window.RudderSnippetVersion = "3.2.0";', + ' var e = "rudderanalytics";', + ' window[e] || (window[e] = []);', + ' var rudderanalytics = window[e];', + ' if (Array.isArray(rudderanalytics)) {', + ' if (true === rudderanalytics.snippetExecuted && window.console && console.error) {', + ' console.error("RudderStack JavaScript SDK snippet included more than once.");', + ' } else {', + ' rudderanalytics.snippetExecuted = true;', + ' window.rudderAnalyticsBuildType = "legacy";', + ' var sdkBaseUrl = "https://cdn.rudderlabs.com";', + ' var sdkVersion = "v3";', + ' var sdkFileName = "rsa.min.js";', + ' var scriptLoadingMode = "async";', + ' var methods = ["setDefaultInstanceKey", "load", "ready", "page", "track", "identify", "alias", "group", "reset", "setAnonymousId", "startSession", "endSession", "consent", "addCustomIntegration"];', + ' for (var n = 0; n < methods.length; n++) {', + ' var method = methods[n];', + ' rudderanalytics[method] = function(methodName) {', + ' return function() {', + ' var instance;', + ' Array.isArray(window[e])', + ' ? rudderanalytics.push([methodName].concat(Array.prototype.slice.call(arguments)))', + ' : (instance = window[e][methodName]) && instance.apply(window[e], arguments);', + ' };', + ' }(method);', + ' }', + ' try {', + ` new Function("class Test{field=()=>{};test({prop=[]}={}){return prop?(prop?.property??[...prop]):import('');}}");`, + ' window.rudderAnalyticsBuildType = "modern";', + ' } catch (error) {}', + ' var head = document.head || document.getElementsByTagName("head")[0];', + ' var body = document.body || document.getElementsByTagName("body")[0];', + ' window.rudderAnalyticsAddScript = function(src, attrName, attrValue) {', + ' var script = document.createElement("script");', + ' script.src = src;', + ' script.setAttribute("data-loader", "RS_JS_SDK");', + ' if (attrName && attrValue) script.setAttribute(attrName, attrValue);', + ' if ("async" === scriptLoadingMode) script.async = true;', + ' else if ("defer" === scriptLoadingMode) script.defer = true;', + ' if (head) head.insertBefore(script, head.firstChild);', + ' else body.insertBefore(script, body.firstChild);', + ' };', + ' window.rudderAnalyticsMount = function() {', + ' !function() {', + ' if ("undefined" == typeof globalThis) {', + ' var globalObject = function getGlobal() {', + ' return "undefined" != typeof self ? self : "undefined" != typeof window ? window : null;', + ' }();', + ' if (globalObject) Object.defineProperty(globalObject, "globalThis", { value: globalObject, configurable: true });', + ' }', + ' }();', + ' window.rudderAnalyticsAddScript(', + ' "".concat(sdkBaseUrl, "/").concat(sdkVersion, "/").concat(window.rudderAnalyticsBuildType, "/").concat(sdkFileName),', + ` "data-rsa-write-key", ${writeKeyJs}`, + ' );', + ' };', + ' if ("undefined" == typeof Promise || "undefined" == typeof globalThis) {', + ' window.rudderAnalyticsAddScript(', + ' "https://polyfill-fastly.io/v3/polyfill.min.js?version=3.111.0&features=Symbol%2CPromise&callback=rudderAnalyticsMount"', + ' );', + ' } else {', + ' window.rudderAnalyticsMount();', + ' }', + ' var loadOptions = {};', + ` rudderanalytics.load(${writeKeyJs}, ${dataplaneUrlJs}, loadOptions);`, + ' rudderanalytics.page();', + ' }', + ' }', + '}();', + ].join('\n') + : ''; + +const scriptHtml = enabled + ? `<script>${scriptBody.replace(/<\/script/gi, '<\\/script')}</script>` + : ''; +--- + +<Fragment set:html={scriptHtml} /> \ No newline at end of file diff --git a/src/components/VideoEmbed.astro b/src/components/VideoEmbed.astro new file mode 100644 index 0000000..1e37b3d --- /dev/null +++ b/src/components/VideoEmbed.astro @@ -0,0 +1,219 @@ +--- +interface Props { + url: string; + title?: string; +} + +const { url, title = '' } = Astro.props; + +const ALLOW = 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'; + +// Match the video id whether it appears as `youtu.be/<ID>`, `youtube.com/watch?v=<ID>`, +// or anywhere later in the query string (e.g. `?feature=youtu.be&v=<ID>`, +// `?t=18s&v=<ID>`, `?ab_channel=Warp&v=<ID>`). The previous regex required `?v=` +// to come immediately after `/watch`, so URLs with any other param first fell +// through and rendered as a plain link instead of an embed. +const ytMatch = + url.match(/youtu\.be\/([\w-]+)/) || + url.match(/youtube\.com\/watch\?(?:[^#]*&)?v=([\w-]+)/); +const loomMatch = url.match(/loom\.com\/share\/([\w-]+)/); +const driveMatch = url.match(/drive\.google\.com\/file\/d\/([\w-]+)/); + +// Convert YouTube watch-page time params (`start`, `end`, `t`) into the +// embed-iframe params so timestamped links keep their start/end behavior. +// `t` accepts `90`, `90s`, or `1m30s` style values; we normalize to seconds. +function parseYtTime(raw: string | null): number | null { + if (!raw) return null; + if (/^\d+$/.test(raw)) return parseInt(raw, 10); + const m = raw.match(/(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?/); + if (!m) return null; + const [, h, mn, s] = m; + if (!h && !mn && !s) return null; + return (parseInt(h ?? '0', 10) * 3600) + (parseInt(mn ?? '0', 10) * 60) + parseInt(s ?? '0', 10); +} + +let kind: 'youtube' | 'loom' | 'drive' | null = null; +let videoId = ''; +let iframeSrc = ''; +if (ytMatch) { + kind = 'youtube'; + videoId = ytMatch[1]; + // Pull start/end/t out of the original URL's query string so we can forward + // them to the embed. URL parsing handles both `youtu.be/<ID>?t=…` and + // `youtube.com/watch?…` forms. + let qs: URLSearchParams | null = null; + try { + qs = new URL(url).searchParams; + } catch { + qs = null; + } + const start = parseYtTime(qs?.get('start') ?? qs?.get('t') ?? null); + const end = parseYtTime(qs?.get('end') ?? null); + const params = new URLSearchParams(); + if (start != null) params.set('start', String(start)); + if (end != null) params.set('end', String(end)); + const query = params.toString(); + iframeSrc = `https://www.youtube-nocookie.com/embed/${videoId}${query ? `?${query}` : ''}`; +} else if (loomMatch) { + kind = 'loom'; + videoId = loomMatch[1]; + iframeSrc = `https://www.loom.com/embed/${videoId}`; +} else if (driveMatch) { + kind = 'drive'; + videoId = driveMatch[1]; + iframeSrc = `https://drive.google.com/file/d/${videoId}/preview`; +} + +const posterAlt = title || (kind === 'youtube' ? 'YouTube video' : ''); +--- + +{kind === 'youtube' ? ( + <div class="video-embed video-embed--lazy"> + {/* Click-to-load facade. Defers ~870KB of YouTube player JS/CSS/fonts + until the user actually plays the video. */} + <button + type="button" + class="video-embed__poster" + data-video-kind="youtube" + data-video-id={videoId} + data-video-title={title} + data-video-start={(() => { + try { return new URL(iframeSrc).searchParams.get('start') ?? undefined; } catch { return undefined; } + })()} + data-video-end={(() => { + try { return new URL(iframeSrc).searchParams.get('end') ?? undefined; } catch { return undefined; } + })()} + aria-label={`Play video${title ? `: ${title}` : ''}`} + > + <img + src={`https://i.ytimg.com/vi/${videoId}/sddefault.jpg`} + alt={posterAlt} + loading="lazy" + decoding="async" + width="640" + height="480" + /> + <span class="video-embed__play" aria-hidden="true"> + <svg viewBox="0 0 68 48" xmlns="http://www.w3.org/2000/svg"> + <path d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z" fill="#f00"/> + <path d="M45 24 27 14v20" fill="#fff"/> + </svg> + </span> + </button> + </div> +) : kind ? ( + <div class="video-embed"> + {/* No `frameborder` attribute — it's removed from HTML5 and the scoped + `.video-embed :global(iframe) { border: 0 }` rule below already + zeroes the border. */} + <iframe + src={iframeSrc} + title={title} + loading="lazy" + allow={ALLOW} + allowfullscreen + /> + </div> +) : ( + <p><a href={url} target="_blank" rel="noopener noreferrer">{title || url}</a></p> +)} + +<script> + // Replace any YouTube poster with a real iframe on click. Single delegated + // listener per page works for any number of <VideoEmbed url="...youtube..."> + // instances on the same page. + document.addEventListener('click', (event) => { + const t = event.target instanceof Element ? event.target.closest('.video-embed__poster') : null; + if (!(t instanceof HTMLElement)) return; + if (t.dataset.videoKind !== 'youtube') return; + const wrapper = t.parentElement; + if (!wrapper) return; + event.preventDefault(); + const id = t.dataset.videoId || ''; + const title = t.dataset.videoTitle || ''; + // Preserve any start/end params encoded on the poster (set server-side from + // the source URL) so the click-to-load path keeps the same timestamp + // behavior as the SSR fallback iframe. + const startParam = t.dataset.videoStart; + const endParam = t.dataset.videoEnd; + const params = new URLSearchParams(); + params.set('autoplay', '1'); + if (startParam) params.set('start', startParam); + if (endParam) params.set('end', endParam); + const iframe = document.createElement('iframe'); + iframe.src = `https://www.youtube-nocookie.com/embed/${id}?${params.toString()}`; + iframe.title = title; + // No `frameborder` — deprecated in HTML5; visual border is zeroed via CSS. + iframe.setAttribute('allow', + 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture' + ); + iframe.setAttribute('allowfullscreen', ''); + wrapper.replaceChild(iframe, t); + }); +</script> + +<style> + .video-embed { + position: relative; + padding-bottom: 56.25%; /* 16:9 */ + height: 0; + overflow: hidden; + margin: 1rem 0; + border-radius: var(--sl-radius-lg); + background: #000; + } + .video-embed :global(iframe) { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: 0; + } + .video-embed__poster { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + padding: 0; + border: 0; + background: #000; + cursor: pointer; + overflow: hidden; + } + .video-embed__poster img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; + opacity: 0.9; + transition: opacity 0.15s ease; + } + .video-embed__poster:hover img, + .video-embed__poster:focus-visible img { + opacity: 1; + } + .video-embed__play { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 68px; + height: 48px; + pointer-events: none; + transition: transform 0.15s ease; + } + .video-embed__play svg { + width: 100%; + height: 100%; + display: block; + } + .video-embed__poster:hover .video-embed__play, + .video-embed__poster:focus-visible .video-embed__play { + transform: translate(-50%, -50%) scale(1.05); + } + .video-embed__poster:focus-visible { + outline: 2px solid var(--sl-color-accent-high); + outline-offset: 2px; + } +</style> diff --git a/src/components/WarpTopbar.astro b/src/components/WarpTopbar.astro new file mode 100644 index 0000000..28d98ab --- /dev/null +++ b/src/components/WarpTopbar.astro @@ -0,0 +1,347 @@ +--- +/** + * Slim Warp brand topbar for standalone pages that don't sit inside Starlight + * (currently just `/api`). Renders the Warp wordmark + a breadcrumb + a small + * nav so the page reads as part of the same surface as the docs. + * + * The host page must reserve `--warp-topbar-height` (3.5rem by default) at + * the top of the viewport — see `src/pages/api.astro` where the same value + * feeds Scalar's `--scalar-y-offset` so its sticky sidebar clears the bar. + * + * Light/dark logo swap is keyed off the host's `.light-mode`/`.dark-mode` + * class on `<body>` (Scalar pattern). If you reuse this on a Starlight- + * themed page, wire similar classes or generalise the toggle. + */ +import logoDark from '../assets/warp-logo-dark.svg?raw'; +import logoLight from '../assets/warp-logo-light.svg?raw'; + +interface NavLink { + href: string; + label: string; + /** Hide on narrow screens (≤ 640px). */ + hideOnNarrow?: boolean; + external?: boolean; +} + +interface Props { + /** Breadcrumb text after the wordmark (e.g. "API Reference"). */ + crumb: string; + /** Right-side nav links. Defaults match the /api page. */ + links?: NavLink[]; +} + +const { + crumb, + // No "active" treatment here — every link in this topbar navigates back + // into the Starlight docs, so there's no current-page surface to + // highlight. The topbar exists to anchor `/api` visually to the rest of + // the docs, not to indicate location within a tab set. + links = [ + { href: '/reference/api-and-sdk/', label: 'API & SDK', hideOnNarrow: true }, + { href: '/reference/api-and-sdk/quickstart/', label: 'Quickstart', hideOnNarrow: true }, + ], +} = Astro.props; +--- + +<header class="warp-topbar" role="banner"> + {/* Wordmark links to warp.dev (matches CustomSiteTitle.astro on Starlight + pages). Users still get to docs root via the explicit "← Docs" link in + the right nav below. */} + <a href="https://warp.dev" class="warp-topbar__home" aria-label="Visit warp.dev"> + <span class="warp-topbar__logo warp-topbar__logo--dark" aria-hidden="true" set:html={logoDark} /> + <span class="warp-topbar__logo warp-topbar__logo--light" aria-hidden="true" set:html={logoLight} /> + <span class="warp-topbar__sep" aria-hidden="true">/</span> + <span class="warp-topbar__crumb">{crumb}</span> + </a> + <div class="warp-topbar__right"> + <nav class="warp-topbar__nav" aria-label="Site"> + <a href="/" class="warp-topbar__link"> + <svg aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> + <path d="M19 12H5"/><path d="m12 19-7-7 7-7"/> + </svg> + <span>Docs</span> + </a> + {links.map((link) => ( + <a + href={link.href} + class:list={['warp-topbar__link', link.hideOnNarrow && 'warp-topbar__link--hide-narrow']} + target={link.external ? '_blank' : undefined} + rel={link.external ? 'noopener' : undefined} + > + {link.label} + </a> + ))} + </nav> + {/* Theme select — mirrors Starlight's ThemeSelect (Auto / Light / Dark) + so the picker lives in the same top-right slot as on the docs side + and shares `localStorage['starlight-theme']` for cross-page persistence. + Native `<select>` is positioned over the visible chip with `opacity:0` + so we get keyboard semantics + native dropdown UI for free. */} + <div class="warp-topbar__theme" data-warp-theme> + <span class="warp-topbar__theme-icon" aria-hidden="true" data-warp-theme-icon> + {/* Default icon paints the auto/laptop glyph; the inline script + below swaps it to sun/moon when the stored value is light/dark. */} + <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> + <rect x="2" y="4" width="20" height="13" rx="2"/> + <path d="M2 21h20"/> + </svg> + </span> + <svg class="warp-topbar__theme-caret" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"> + <path d="m6 9 6 6 6-6"/> + </svg> + <select aria-label="Theme" data-warp-theme-select> + <option value="auto">Auto</option> + <option value="light">Light</option> + <option value="dark">Dark</option> + </select> + </div> + </div> +</header> + +<style> + /* A slim brand bar that mirrors the Starlight site nav so standalone pages + feel like part of the same surface. The matching `--warp-topbar-height` + token in the host page's CSS feeds `--scalar-y-offset` (or equivalent) + so any sticky content clears the bar. + + Default is 3.5rem (matches Starlight's `--sl-nav-height` mobile value); + the host page bumps the token to 4rem at >=50em so the bar lines up + with Starlight's desktop nav and the logo doesn't jump vertically when + you navigate from /docs to /api. */ + .warp-topbar { + position: sticky; + top: 0; + z-index: 50; + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + height: var(--warp-topbar-height, 3.5rem); + padding: 0 1rem; + background: var(--scalar-background-1, #121212); + border-bottom: 1px solid var(--scalar-border-color, rgba(255, 255, 255, 0.08)); + font-family: var(--scalar-font, 'Inter', sans-serif); + color: var(--scalar-color-1, #fafafa); + } + .warp-topbar__home { + display: inline-flex; + align-items: center; + gap: 0.625rem; + text-decoration: none; + color: inherit; + min-width: 0; + padding: 0.25rem 0.375rem; + margin-left: -0.375rem; + border-radius: var(--sl-radius-md); + } + .warp-topbar__home:hover { background: var(--scalar-background-2); } + .warp-topbar__home:focus-visible { + outline: 2px solid var(--scalar-color-accent); + outline-offset: 2px; + } + .warp-topbar__logo { + display: inline-flex; + align-items: center; + flex-shrink: 0; + } + .warp-topbar__logo :global(svg), + .warp-topbar__logo > svg { + height: 1.25rem; + width: auto; + max-width: 100%; + display: block; + } + /* Light/dark logo swap, keyed off the host's .light-mode/.dark-mode class. */ + .warp-topbar__logo--dark { display: none; } + body.dark-mode .warp-topbar__logo--dark { display: inline-flex; } + body.dark-mode .warp-topbar__logo--light { display: none; } + .warp-topbar__sep { + color: var(--scalar-color-3); + opacity: 0.6; + font-weight: 300; + font-size: 1rem; + } + .warp-topbar__crumb { + color: var(--scalar-color-2); + font-size: 0.875rem; + font-weight: 500; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + /* Right group wraps the nav and the theme select so the topbar's + `justify-content: space-between` keeps the home/crumb pinned left and + the whole right cluster pinned right. */ + .warp-topbar__right { + display: inline-flex; + align-items: center; + gap: 1rem; + } + /* Right-side nav: every link is an outbound jump to the Starlight docs, + so there's no "active" tab to indicate. We keep the calm gray-3 idle + → full-emphasis white hover progression from the topic nav, but drop + the accent underline + active treatment — nothing here is the + current page. */ + .warp-topbar__nav { + display: inline-flex; + align-items: center; + gap: 1.25rem; + } + .warp-topbar__link { + /* Flat type, no chip surface. `--scalar-color-3` / `-color-1` are the + Scalar equivalents of `--sl-color-gray-3` / `-color-white`, mapped + to Warp brand tokens in `pages/api.astro`. Visual weight lives + entirely in the type color shift on hover. */ + display: inline-flex; + align-items: center; + gap: 0.375rem; + padding: 0 0.125rem; + text-decoration: none; + color: var(--scalar-color-3); + font-size: 0.8125rem; + font-weight: 500; + line-height: 1.25; + transition: color 0.15s ease; + white-space: nowrap; + } + .warp-topbar__link:hover { + color: var(--scalar-color-1); + } + .warp-topbar__link:focus-visible { + outline: 2px solid var(--scalar-color-accent); + outline-offset: 2px; + border-radius: var(--sl-radius-xs); + } + /* Theme select chip. The visible chrome is `[icon] [caret]`; the actual + `<select>` sits on top with `opacity: 0` so clicks/keyboard open the + native dropdown but the chip carries the styling. We rely on `:has()` + for keyboard-only focus (modern browsers, gracefully degrades to no + focus ring on older ones — the underlying select still gets the + native keyboard outline if the chip's outline doesn't apply). */ + .warp-topbar__theme { + position: relative; + display: inline-flex; + align-items: center; + gap: 0.25rem; + height: 2rem; + padding: 0 0.375rem; + border-radius: var(--sl-radius-sm); + color: var(--scalar-color-3); + cursor: pointer; + transition: color 0.15s ease, background-color 0.15s ease; + } + .warp-topbar__theme:hover { + color: var(--scalar-color-1); + background: var(--scalar-background-2); + } + .warp-topbar__theme:has(select:focus-visible) { + outline: 2px solid var(--scalar-color-accent); + outline-offset: 2px; + } + .warp-topbar__theme-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 14px; + height: 14px; + } + .warp-topbar__theme-icon :global(svg) { + width: 14px; + height: 14px; + display: block; + } + .warp-topbar__theme-caret { + display: inline-flex; + opacity: 0.7; + } + .warp-topbar__theme select { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + margin: 0; + padding: 0; + border: 0; + background: transparent; + color: inherit; + font: inherit; + opacity: 0; + cursor: pointer; + appearance: none; + } + .warp-topbar__theme select:focus { + outline: none; + } + @media (max-width: 640px) { + .warp-topbar { padding: 0 0.75rem; } + .warp-topbar__sep, + .warp-topbar__crumb { display: none; } + .warp-topbar__link--hide-narrow { display: none; } + } +</style> + +<script is:inline> + // Theme select wiring (drives `localStorage['starlight-theme']` so it + // round-trips with Starlight's own ThemeSelect on the docs side). The + // heavy lifting — resolving auto, applying body class, syncing across + // tabs and `prefers-color-scheme` changes — lives in the inline init + // script in `pages/api.astro`, exposed as `window.__warpApplyTheme`. + // This script just wires the select UI up to that helper and keeps the + // visible icon in sync with the stored value. + (function () { + var root = document.querySelector('[data-warp-theme]'); + if (!root) return; + var select = root.querySelector('[data-warp-theme-select]'); + var iconWrap = root.querySelector('[data-warp-theme-icon]'); + if (!select || !iconWrap) return; + // Inline SVGs match the visual weight of Starlight's `sun`/`moon`/ + // `laptop` icons in `node_modules/@astrojs/starlight/components-internals/Icons.ts`. + var ICONS = { + auto: '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="13" rx="2"/><path d="M2 21h20"/></svg>', + light: '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></svg>', + dark: '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>', + }; + var read = function () { + try { + var v = localStorage.getItem('starlight-theme'); + return v === 'light' || v === 'dark' ? v : 'auto'; + } catch (_e) { return 'auto'; } + }; + var setIcon = function (v) { + iconWrap.innerHTML = ICONS[v] || ICONS.auto; + }; + var setValue = function (v) { + select.value = v; + setIcon(v); + }; + setValue(read()); + select.addEventListener('change', function () { + var v = select.value; + setIcon(v); + if (typeof window.__warpApplyTheme === 'function') { + window.__warpApplyTheme(v); + } else { + // Fallback: write to storage and apply minimally. Used only if the + // page-level helper isn't loaded (e.g. WarpTopbar reused outside + // /api in the future). + try { + localStorage.setItem('starlight-theme', v === 'auto' ? '' : v); + } catch (_e) {} + var resolved = v === 'auto' + ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') + : v; + document.body.classList.toggle('dark-mode', resolved === 'dark'); + document.body.classList.toggle('light-mode', resolved !== 'dark'); + document.documentElement.setAttribute('data-theme', resolved); + } + }); + // Cross-tab sync: another tab updated the preference — mirror it in + // our select UI. (The page-level script in api.astro handles + // re-applying the resolved theme; we just keep the icon honest here.) + window.addEventListener('storage', function (e) { + if (e.key !== 'starlight-theme') return; + var v = e.newValue; + setValue(v === 'light' || v === 'dark' ? v : 'auto'); + }); + })(); +</script> diff --git a/src/components/WarpTopicNav.astro b/src/components/WarpTopicNav.astro new file mode 100644 index 0000000..46f5094 --- /dev/null +++ b/src/components/WarpTopicNav.astro @@ -0,0 +1,262 @@ +--- +// Horizontal topic navigation for the top header (Scalar-style). +// +// Renders one link per topic configured in `src/sidebar.ts` (Terminal, Agents, +// Reference, etc.) as an inline-flex row with a small icon + label. The list +// is sourced from `starlight-sidebar-topics`'s middleware, which exposes +// `Astro.locals.starlightSidebarTopics.topics` on every Starlight route. +// Each topic carries `{ link, label, icon, badge, isCurrent }`; we consume +// `link`/`label`/`icon`/`isCurrent` and ignore `badge` for now (none of our +// topics ship one). The plugin's per-topic sidebar filtering lives in its +// middleware (it rewrites `starlightRoute.sidebar`), so removing the topic +// list from the sidebar markup does NOT break that filtering — the same +// filtered nav still renders below this row in the page sidebar. +// +// Visual spec: +// - 14px label, weight 500, calm gray-3 idle (dim enough that the active +// link reads clearly without an outline or background) +// - 12×12 icon, color inherits from the link. Sized to roughly match +// Inter's cap-height at 14px (≈10.1px) so the icon's element box sits +// inside the visible glyph range — geometric centering then equals +// optical centering, no per-icon transform needed (Vercel/Stripe nav +// pattern). +// - Active link: accent-blue text + weight 600 + 2px accent underline +// anchored to the header's bottom edge so the line visually replaces the +// header hairline under the active item (Scalar pattern). Text and +// underline share `--sl-color-text-accent`, which auto-adapts to dark +// and light themes. +// - No surrounding chip / box / bg — just type + icon +import { Icon } from '@astrojs/starlight/components'; + +const { topics } = Astro.locals.starlightSidebarTopics; + +// Per-topic icon overrides for topics where Starlight's icon registry doesn't +// ship the right glyph (only 22 generic UI icons available; no robot/AI). The +// `sidebar.ts` config keeps the closest Starlight name (e.g. `puzzle` for +// Agents, `seti:json` for API) so the mobile drawer falls back gracefully; +// this map points to a custom inline SVG that we render here in the header +// instead. +const CUSTOM_TOPIC_ICONS: Record<string, true> = { + Agents: true, + API: true, +}; +--- + +{topics && topics.length > 0 && ( + <nav class="warp-topic-nav" aria-label="Documentation sections"> + <ul> + {topics.map((topic) => ( + <li> + <a + href={topic.link} + aria-current={topic.isCurrent ? 'page' : undefined} + > + {CUSTOM_TOPIC_ICONS[topic.label] ? ( + <span class="warp-topic-nav__icon" aria-hidden="true"> + {/* No inline width/height on either custom SVG — the + `.warp-topic-nav__icon :global(svg)` rule below pins + this and the Starlight-rendered icons to a single + uniform size. `currentColor` so each icon inherits the + link's text color and picks up the active-state accent. */} + {topic.label === 'API' ? ( + /* `</>` brackets — the conventional dev-API glyph. + Two chevrons mirrored across center, stroke weight + matched to the other topic icons. */ + <svg + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="2" + stroke-linecap="round" + stroke-linejoin="round" + > + <path d="M16 18l6-6-6-6" /> + <path d="M8 6l-6 6 6 6" /> + </svg> + ) : ( + /* Robot icon — stroke-based outline matching the visual + weight of Starlight's other topic icons (laptop, book, + star). Antenna on top, rounded square head, two eyes, + mouth line, two stubby arms. */ + <svg + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="2" + stroke-linecap="round" + stroke-linejoin="round" + > + <rect x="4" y="7" width="16" height="13" rx="2.5" /> + <line x1="12" y1="3" x2="12" y2="7" /> + <circle cx="12" cy="3" r="0.6" fill="currentColor" /> + <circle cx="9" cy="13" r="1" fill="currentColor" stroke="none" /> + <circle cx="15" cy="13" r="1" fill="currentColor" stroke="none" /> + <line x1="9" y1="17" x2="15" y2="17" /> + <line x1="4" y1="13" x2="2" y2="13" /> + <line x1="22" y1="13" x2="20" y2="13" /> + </svg> + )} + </span> + ) : topic.icon ? ( + <span class="warp-topic-nav__icon" aria-hidden="true"> + <Icon name={topic.icon} /> + </span> + ) : null} + <span class="warp-topic-nav__label">{topic.label}</span> + </a> + </li> + ))} + </ul> + </nav> +)} + +<style> + .warp-topic-nav { + /* Sits between SiteTitle and the right control group inside `.header`. + The header itself is `display: flex; align-items: center;` — this + nav uses `align-self: stretch` so its links can pin a 2px accent + underline to the header's bottom edge. */ + align-self: stretch; + display: flex; + align-items: stretch; + min-width: 0; + } + + ul { + list-style: none; + margin: 0; + padding: 0; + display: flex; + align-items: stretch; + gap: 1.25rem; + min-width: 0; + overflow: hidden; + } + + li { + display: flex; + align-items: stretch; + } + + a { + /* Stretches to the full header height so the bottom-anchored `::after` + indicator sits flush with the header hairline (Scalar pattern) — + not under the link's text box. `align-self: stretch` inherits the + parent <li>'s height (which inherits from `<ul>` → nav → header). */ + position: relative; + align-self: stretch; + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0 0.125rem; + font-size: var(--sl-text-sm); + font-weight: 500; + /* `1.25` is just enough to clear Inter's natural ascent + descent + (~1.21em) so descenders in `Changelog` (`g`) and `Reference` + (`f`) aren't clipped, while keeping the line-box close to the + visible text. The link's outer height is set by `align-self: + stretch` on the parent, so this only affects internal text + layout (and the icon's optical centering, see + `.warp-topic-nav__icon` below). */ + line-height: 1.25; + /* Idle color uses `gray-3` so the active link's full-emphasis white + text reads as clearly distinct (and not just "white-on-slightly- + lighter-white"). The accent underline carries the rest of the + active-state weight. */ + color: var(--sl-color-gray-3); + text-decoration: none; + white-space: nowrap; + transition: color 0.15s ease; + } + + a:hover { + color: var(--sl-color-white); + } + + a:focus-visible { + outline: 2px solid var(--sl-color-accent-high); + outline-offset: 4px; + border-radius: var(--sl-radius-xs); + } + + /* Active link picks up the same accent blue as the underline so the + text and indicator read as one unified active state, and it ties + into the rest of the site's blue accents (links, callouts, focus + ring). `--sl-color-text-accent` is theme-aware: a lighter blue in + dark mode, a darker blue in light mode — both keep AA contrast + against the nav background. Weight 600 reinforces it against the + calmer gray-3 idle siblings. */ + a[aria-current='page'] { + color: var(--sl-color-text-accent); + font-weight: 600; + } + + /* 2px accent underline that REPLACES the header's 1px bottom hairline + under the active topic (Scalar pattern). The outer Starlight + `<header class="header">` owns the hairline + (`border-bottom: 1px solid var(--sl-color-hairline-shade)`) and has + `padding-block: var(--sl-nav-pad-y)` with `box-sizing: border-box`, so + the link's bottom edge sits `--sl-nav-pad-y` above the hairline rather + than directly on it. We anchor the indicator at the hairline by + dropping it through the bottom padding (`-var(--sl-nav-pad-y)`) and the + 1px border (`-1px`); `height: 2px` then paints across both, leaving the + blue accent as the only line at that position under the active tab. + The remainder of the header keeps its hairline. */ + a[aria-current='page']::after { + content: ''; + position: absolute; + left: 0; + right: 0; + bottom: calc(-1 * var(--sl-nav-pad-y) - 1px); + height: 2px; + background: var(--sl-color-text-accent); + } + + .warp-topic-nav__icon { + display: inline-flex; + align-items: center; + justify-content: center; + flex: none; + color: inherit; + /* No optical-centering transform here. The icon is sized at 12px + (see `:global(svg)` below) which is just under Inter's + cap-height at 14px font (≈10.1px in glyph terms but the icon's + visible mark fills more of its 12px box than Inter's caps fill + their em-box). With the icon's element box ≈ the visible text's + vertical extent, `align-items: center` on the link lands the + icon's geometric center within the glyph range — which reads as + optically centered without any per-icon translateY hack. This + also dodges the issue that different Starlight icons place + their visible mass at slightly different y positions inside + their 24×24 viewBox (e.g. `laptop` is shifted up; `star` and + `open-book` are centered). */ + } + + .warp-topic-nav__icon :global(svg) { + /* 12px is one notch below Inter's cap-height at 14px font, so the + icon's element box sits inside the visible text's vertical + extent rather than straddling it. Pinned via this single rule + so the inline robot SVG above and the Starlight-rendered icons + share a uniform size. */ + width: 12px; + height: 12px; + display: block; + } + + .warp-topic-nav__label { + display: inline-block; + } + + /* Mid-width fallback. Below ~80rem (~1280px) the 8 topic items + logo + + right-group start to crowd. Drop the per-item icons first so the labels + keep room. The mobile drawer (rendered separately) takes over below + 50rem where this nav is hidden entirely. */ + @media (max-width: 80rem) { + ul { + gap: 1rem; + } + .warp-topic-nav__icon { + display: none; + } + } +</style> diff --git a/src/content.config.ts b/src/content.config.ts new file mode 100644 index 0000000..7097d02 --- /dev/null +++ b/src/content.config.ts @@ -0,0 +1,11 @@ +import { defineCollection } from 'astro:content'; +import { docsLoader } from '@astrojs/starlight/loaders'; +import { docsSchema } from '@astrojs/starlight/schema'; +import { topicSchema } from 'starlight-sidebar-topics/schema'; + +export const collections = { + // `topicSchema` adds a `topic` frontmatter field used by + // `starlight-sidebar-topics` to associate unlisted pages with a topic ID. + // See guides/agent-workflows/warp-vs-claude-code.mdx for an example. + docs: defineCollection({ loader: docsLoader(), schema: docsSchema({ extend: topicSchema }) }), +}; diff --git a/src/content/docs/agent-platform/capabilities/agent-notifications.mdx b/src/content/docs/agent-platform/capabilities/agent-notifications.mdx new file mode 100644 index 0000000..ef50787 --- /dev/null +++ b/src/content/docs/agent-platform/capabilities/agent-notifications.mdx @@ -0,0 +1,97 @@ +--- +title: Agent Notifications +description: >- + Warp surfaces notifications from coding agents, both in-app and via desktop + alerts, so you know exactly when an agent needs your attention. +--- + +Warp delivers notifications from any supported coding agent so you always know when an agent finishes a task, encounters an error, or needs your input. Notifications work whether you're in a different tab or a different app. + +## Notification types + +Warp categorizes agent notifications by what happened: + +* **Complete** - the agent finished its task successfully. You can review the output and continue working. +* **Request** - the agent is blocked and needs your input. This includes command approval, permission requests, and idle prompts where the agent is waiting for you. +* **Error** - the agent encountered an error that requires your attention. + +## In-app notifications + +When you're working in Warp but not looking at the agent's tab, Warp provides several visual signals. + +### Toast notifications + +Floating toast notifications appear in the corner of the Warp window when an agent in another tab needs attention. Toasts auto-dismiss after a few seconds. Hover over a toast to pause the timer, or click it to jump directly to the agent's session. + +Up to two toasts are visible at a time. If additional notifications arrive, the oldest toast is replaced. + +![A Warp toast notification in the upper-right corner showing an agent task completed, with an Open conversation action and a keyboard shortcut chip](../../../../assets/agent-platform/toast-notification.png) + +### Notification mailbox + +The notification mailbox is a sidebar panel that collects all agent notifications in one place. Open it from the bell icon in the top-right corner of Warp. + +![The Warp notification mailbox open in the upper-right of the window with All tabs and Unread filter tabs, a Mark all as read action, and a notification entry](../../../../assets/agent-platform/notification-mailbox.png) + +The mailbox includes: + +* **Filter tabs** - switch between **All tabs**, **Unread**, and **Errors** to find what needs attention. If there are no unreads or errors, those filters don't appear. +* **Mark all as read** - clear all unread indicators at once +* **Click to navigate** - click any notification to jump directly to that agent's tab + +**Keyboard shortcuts:** + +* `↑` / `↓` - select previous / next notification +* `Enter` - open the selected notification's session +* `Shift-Tab` - cycle through filter tabs +* `Esc` - close the mailbox + +### Tab status indicators + +Each tab displays an icon reflecting its agent's current state — working, blocked, completed, or errored. Tabs with unread notifications show an attention badge so you can spot which sessions need action, even with many tabs open. + +{/* TODO: Add screenshot showing tab bar with status icons and attention badges */} + +Notifications are automatically marked as read when you navigate to the agent's tab. + +## Desktop notifications + +When Warp is in the background or minimized, agent notifications are delivered as native system-level desktop alerts. This ensures you're aware of agent activity even while working in other apps. + +{/* TODO: Add screenshot showing a native desktop notification from Warp */} + +:::note +Desktop notifications require system permissions. If you're not receiving them, check your OS notification settings for Warp. See [Desktop Notifications](/terminal/more-features/notifications/) for setup and troubleshooting. +::: + +## Supported agents + +Agent notifications currently work with: + +* **Oz agent** - supported out of the box. No setup required. +* **Claude Code** - full support via notification plugin. +* **Codex** - full support via native Codex configuration. +* **OpenCode** - full support via notification plugin. + +## Setting up notifications + +For the **Oz agent**, notifications work out of the box — no setup needed. + +For **third-party CLI agents**, each agent requires a one-time setup. The process varies by agent: + +* **Claude Code** - one-click auto-install via a chip in Warp, or manual plugin commands. See [Claude Code setup](/agent-platform/cli-agents/claude-code/#setting-up-notifications). +* **Codex** - add `notification_condition = "always"` under `[tui]` in `~/.codex/config.toml`, then restart Codex. See [Codex setup](/agent-platform/cli-agents/codex/#setting-up-notifications). +* **OpenCode** - add `"@warp-dot-dev/opencode-warp"` to the `plugin` array in your OpenCode config. See [OpenCode setup](/agent-platform/cli-agents/opencode/#setting-up-notifications). + +![The Enable Claude Code notifications chip in the agent utility bar with a tooltip reading Install the Warp plugin to enable rich agent notifications within Warp](../../../../assets/agent-platform/enable-cli-agent-notifications.png) + +If auto-install doesn't work or you're running an agent over SSH, Warp displays an installation-instructions chip in the terminal with setup steps you can follow directly. + +## Related pages + +* [Desktop Notifications](/terminal/more-features/notifications/) - configure system-level notification permissions and troubleshoot delivery +* [Managing Agents](/agent-platform/cloud-agents/managing-cloud-agents/) - monitor all agent conversations, filter by status, and inspect sessions +* [Third-Party CLI Agents](/agent-platform/cli-agents/overview/) - overview of supported CLI agents and Warp features +* [Claude Code](/agent-platform/cli-agents/claude-code/) - setup and notification plugin installation +* [Codex](/agent-platform/cli-agents/codex/) - setup and notification configuration +* [OpenCode](/agent-platform/cli-agents/opencode/) - setup and notification plugin installation diff --git a/src/content/docs/agent-platform/capabilities/agent-profiles-permissions.mdx b/src/content/docs/agent-platform/capabilities/agent-profiles-permissions.mdx new file mode 100644 index 0000000..d1cbaa0 --- /dev/null +++ b/src/content/docs/agent-platform/capabilities/agent-profiles-permissions.mdx @@ -0,0 +1,125 @@ +--- +title: "Profiles & Permissions" +description: >- + Agent Profiles let you customize how your Agent behaves, from its models and + autonomy to the tools and permissions it can use. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +## Agent Profiles + +Agent Profiles let you configure how your Agent behaves in different situations. Each profile defines the Agent's autonomy, base models, and tool access. You can create multiple profiles and edit them directly in **Settings** > **Agents** > **Profiles**. + +* **Default profile**: Every user starts with a default profile, you can edit it at any time, and new profiles will copy its settings as a starting point. +* **Other profiles**: Set up different profiles for different workflows (e.g., "Safe & cautious", "YOLO mode", etc.). Manage them in the Profiles settings menu. + +![Agent Profiles in Settings: define how your Agent operates.](../../../../assets/agent-platform/agent-profiles.png) + +**In each Agent Profile, you can configure:** + +* The name of the profile +* **Base model**: The core engine for your Agent. It handles most interactions and invokes other models when needed (e.g. for code generation). This model is also used for [Planning](/agent-platform/capabilities/planning/) by default, though you can configure a separate planning model. +* Agent autonomy and permissions + +![Agent Profiles in Settings: editing a Profile.](../../../../assets/agent-platform/agent-profiles-settings.png) + +## Agent Permissions + +Agent Permissions let you define how your Agent in a specific Profile operates — control its autonomy, choose what tools or MCP servers it can access, and set when it should act independently or ask for approval. + +:::caution +**Still getting approval prompts?** If the Agent keeps asking for permission to run certain commands (like `curl`, `rm`, or `wget`) even though you've set permissions to "Always allow," check your **Command denylist** in **Settings** > **Agents** > **Profiles**. The denylist always takes precedence over other permission settings. Remove commands from the denylist to allow them to auto-execute, or use [Run until completion](#run-until-completion) to bypass the denylist for the current task. +::: + +You can control how much autonomy the Agent has when performing different types of actions under **Settings** > **Agents** > **Profiles** > **Permissions** . Agent permission types: + +* Apply code diffs +* Read files +* Create plans +* Execute commands +* Interact with running commands (via [Full Terminal Use](/agent-platform/capabilities/full-terminal-use/)) + +<div align="center">![Fine-tuning agent control: This permissions panel lets users customize how much autonomy the Agent has when applying code diffs, reading files, creating plans, and executing commands.](../../../../assets/agent-platform/agent-permissions-with-full-terminal-use.png)</div> + +**Each permission has different levels of autonomy:** + +<table><thead><tr><th width="196.3369140625">Autonomy level</th><th>Description</th></tr></thead><tbody><tr><td>Agent Decides</td><td>Agent will act autonomously when it's confident, but prompt for approval when uncertain. This option balances speed with control, allowing the Agent to go ahead with common workflows while keeping you in the loop for more complex or risky steps.</td></tr><tr><td>Always ask</td><td>Agent will request explicit user approval before taking any action. Choose this for sensitive actions.</td></tr><tr><td>Always allow</td><td>Agent will perform the action without ever requesting explicit confirmation. Use this for tasks you fully trust the Agent to handle on its own.</td></tr><tr><td>Never</td><td>Agent will not ever take the action (i.e. Create plans).</td></tr></tbody></table> + +:::note +For **Apply code diffs**, `Agent decides` currently behaves the same as `Always ask` — the Agent always prompts you to review diffs before applying them. Only `Always allow` skips the review prompt. + +When all Agent permissions are set to **Always allow**, the Agent gains full autonomy (“YOLO mode”); however, any denylist rules will still override these settings. +::: + +### Command allowlist + +The Agent lets you define an allowlist of commands that run automatically without confirmation. It’s empty by default, but users often add read-only commands such as: + +* `which .*` - Find executable locations +* `ls(\s.*)?` - List directory contents +* `grep(\s.*)?` - Search file contents +* `find .*` - Search for files +* `echo(\s.*)?` - Print text output + +You can add your own regular expressions to this list in **Settings** > **Agents** > **Profiles** > **Command allowlist**. Commands in the allowlist will always auto-execute, even if they are not read-only operations. + +![Command allowlist and denylists as part of an Agent Profile.](../../../../assets/agent-platform/agent-profiles-allow-and-denylists.png) + +### Command denylist + +For safety, the Agent always prompts for confirmation before executing potentially risky commands. The default denylist includes several examples, such as: + +* `wget(\s.*)?` - Network downloads +* `curl(\s.*)?` - Network requests +* `rm(\s.*)?` - File deletion +* `eval(\s.*)?` - Shell code execution + +The denylist takes precedence over both the allowlist and `Agent decides`. If a command matches the denylist, user permission will always be required, regardless of other settings. You can add your own regular expressions to this list in **Settings** > **Agents** > **Profiles** > **Command denylist**. + +### MCP permissions + +MCP servers let you extend the Agent with custom tools and data sources using standardized, plugin-like modules. + +In this settings menu, you can configure which MCP servers the Agent is allowed to call: + +* Use the MCP allowlist to give the Agent permission to call specific servers without asking. +* Use the MCP denylist to require approval before calling certain servers, even if they’re also in the allowlist. +* Or set the Agent to “decide” — it will act autonomously when confident, and ask for confirmation when uncertain. + +![Customize how the Agent interacts with MCP servers by choosing between “Agent decides,” allowlist, or denylist settings.](../../../../assets/agent-platform/MCP_servers_agent_permissions.png) + +:::note +To learn how to build and configure your own MCP server, check out the [MCP feature docs](/agent-platform/capabilities/mcp/). +::: + +## Run until completion + +During an Agent interaction, you can give the Agent full autonomy for the current task. When auto-approve is on, every suggested command runs immediately until the task finishes, or you stop it with `Ctrl + C`. + +<Tabs> + <TabItem label="macOS"> + Auto-approve all Agent actions with: `CMD + SHIFT + I` + </TabItem> + <TabItem label="Windows"> + Auto-approve all Agent actions with: `CTRL + SHIFT + I` + </TabItem> + <TabItem label="Linux"> + Auto-approve all Agent actions with: `CTRL + SHIFT + I` + </TabItem> +</Tabs> + +![A button overlay in the lower-right corner lets you enable auto-approve or end the Agent interaction.](../../../../assets/agent-platform/run-until-completion.png) + +:::note +_Run until completion_ ignores the denylist entirely. It's the purest form of “YOLO” mode and essentially a fully "autonomous mode" where the Agent proceeds without asking for confirmation. +::: + +--- + +## Next steps + +Once you've configured how your agent operates, try giving it a larger task to plan and execute. + +* **[Planning](/agent-platform/capabilities/planning/)** - Break down complex tasks into structured, executable plans that the agent runs step by step. +* **[Code diffs](/agent-platform/local-agents/code-diffs/)** - Review, refine, and apply code changes the agent generates. +* **[Interactive Code Review](/agent-platform/local-agents/interactive-code-review/)** - Leave inline comments on agent-generated diffs and have the agent address your feedback. diff --git a/src/content/docs/agent-platform/capabilities/codebase-context.mdx b/src/content/docs/agent-platform/capabilities/codebase-context.mdx new file mode 100644 index 0000000..2bd8488 --- /dev/null +++ b/src/content/docs/agent-platform/capabilities/codebase-context.mdx @@ -0,0 +1,146 @@ +--- +title: Codebase Context +description: >- + Warp indexes your Git-tracked codebase to help Agents understand your code + and generate accurate, context-aware responses. No code is stored on Warp + servers. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Codebase Context helps Agents understand your project by indexing your local codebase. This allows Agents to generate more accurate completions, suggest context-aware edits, and answer questions using real knowledge of your code. + +## Get started + +Index a project and see the difference in agent responses in a few minutes. + +:::note +**Don't have a project to try?** Clone a popular open-source repo to test out codebase indexing: +```bash +git clone https://github.com/vercel/next.js.git && cd next.js +``` +::: + +1. **Open a project folder in Warp.** Navigate to a Git repository using `cd` or open a folder from the file tree. Warp automatically detects the Git repo and begins indexing. +2. **Verify indexing status.** In Warp, go to **Settings** > **Code** > **Indexing and projects** and check the status under "Initialized / indexed folders." Once the status shows **Synced**, your codebase is ready. +3. **Ask the Agent a question about your code.** Start an Agent conversation (`⌘+Enter` on macOS, `Ctrl+Shift+Enter` on Windows/Linux) and try a prompt like: + * "Explain the architecture of this project" + * "What are the main entry points?" + * "Walk me through the most important modules" +4. **See the difference.** The Agent grounds its responses in actual files, functions, and line numbers from your codebase, producing more accurate and context-aware answers. + +--- + +## Indexing your codebase + +When you open a directory in Warp, we check if it is part of a Git repository. If it is, Warp begins indexing the source code to provide rich context for Agents. Warp also detects [Git worktree](/code/git-worktrees/) checkouts — each worktree is indexed as its own repository, so Agents always have accurate context for the branch you're working on. + +:::note +Code indexed with Codebase Context is never stored on our servers. Codebase Context works with both local agent sessions and [cloud agent runs](/agent-platform/cloud-agents/overview/). Without Codebase Context enabled, agents will still be able use terminal commands (i.e. `grep`, `sed`) to navigate your code. +::: + +:::danger +**Codebase Context doesn't work within SSH or WSL sessions.** \ +\ +Feature requests for support are being tracked in the following GitHub issues: \ +\- SSH: [https://github.com/warpdotdev/Warp/issues/6831](https://github.com/warpdotdev/Warp/issues/6831)\ +\- WSL: [https://github.com/warpdotdev/Warp/issues/6744](https://github.com/warpdotdev/Warp/issues/6744) +::: + +![Codebase indexing settings in Warp. Easily track sync status and manage which folders are indexed for AI-powered context and suggestions.](../../../../assets/agent-platform/codebase-context-main.png) + +**Codebase indexing intervals and triggers:** + +* Initially when you have Codebase Context enabled. +* Warp automatically triggers a codebase index periodically. +* Whenever a new Agent conversation begins. +* When you click on the sync 🔄 button in **Settings** > **Code** > **Indexing and projects**. + +**This embeddings index helps Agents:** + +* Understand your project structure and reference relevant code +* Generate completions that match your style and patterns +* Suggest edits in the correct locations based on real context + +For large projects, indexing may take a few minutes. Agents will not use Codebase Context until indexing is complete, but **agentic coding features remain fully available in the meantime**. + +:::note +You can view and manage your indexed codebases in **Settings** > **Code** > **Indexing and projects** under "Initialized / indexed folders". You can also choose whether to automatically index new folders as you navigate them. +::: + +<VideoEmbed url="https://youtu.be/11rz9OYQ8Hg" /> + +### **Codebase indexing states** + +When viewing indexed codebases in Warp under **Settings** > **Code** > **Indexing and projects**, you may see different status indicators: + +* **Synced** — Indexing is complete and the codebase is ready to be used as context. +* **Discovering files** – Warp is currently scanning and indexing files in the codebase. +* **Failed** – Indexing failed. Common reasons include unreadable `.git` directories or corrupted repositories. Try re-cloning the repo and syncing again. +* **Codebase too large** – The number of files in the codebase exceeds your current plan’s limit. You can either reduce the number of files being indexed using `.warpindexingignore`, or [contact sales](https://warp.dev/contact-sales) for support with larger codebases. + +![View and manage the indexing status of your codebases in Warp. Easily see which projects are synced, in progress, or require attention.](../../../../assets/agent-platform/codebase-context-statuses.png) + +### When does codebase syncing happen? + +Warp automatically triggers a codebase sync initially and periodically, when you click on the sync 🔄 button in **Settings** > **Code** > **Indexing and projects**, or when you start a new Agent conversation. However, if many files have changed or the network is slow, the sync may not complete before the Agent tries to access context. + +:::note +In large projects (e.g. after a branch switch), there may be a short delay where the Agent references stale or outdated files. +::: + +### File and codebase limits + +The number of codebases you can index and the maximum number of files per codebase vary by plan. All plans support indexing **at least 5,000 files per codebase**, with higher tiers including support for more files and additional codebases. + +For full details, visit our [pricing page](https://www.warp.dev/pricing). + +### Ignore files + +For large codebases, Warp supports several ignore files to give you control over what gets indexed. This allows each developer to focus context on the parts of the codebase most relevant to their work. + +Warp respects the following ignore files: + +* `.gitignore` +* `.warpindexingignore` +* `.cursorignore` +* `.cursorindexingignore` +* `.codeiumignore` + +Use these files to skip indexing of folders, generated files, or any content you don't want agents to reference. This can improve performance and result quality. + +:::note +Files excluded by ignore rules **do not** count toward your codebase's file limit. +::: + +## Codebase Context in cloud agent runs + +Codebase Context is available in all Oz cloud agent runs — including runs triggered from the CLI, API/SDK, integrations (Slack, Linear, GitHub Actions), and schedules — as long as Codebase Context is enabled for your account. + +**No additional configuration is needed.** If Codebase Context is enabled, cloud agents use it automatically. + +## Multi-repo context + +Warp supports referencing context across multiple indexed repositories. Note that you don’t need to be inside a specific repo for agents to use its context. + +**This is especially useful when:** + +* Implementing a feature across multiple repos, such as full-stack work across client and server +* Using one repo as a reference while building in another, for example: “copy the implementation from repo A into my repo B” + +Agents will only reference other repositories if they are already indexed. During cross-repo tasks, Warp's Agents have access to the file paths of all indexed repos. It is more likely to use cross-repo context when you mention the exact name of the repo in your prompt. + +## Demo: Explain my codebase with Warp + +Here's an example from [Warp Guides](/guides/), where Zach demonstrates how Warp uses Codebase Context to search for and use the relevant files as context: + +<VideoEmbed url="https://www.youtube.com/watch?v=11rz9OYQ8Hg" /> + +--- + +## Next steps + +With your codebase indexed, you can browse your project directly in Warp and start letting agents take action on your code. + +* **[File Tree](/code/code-editor/file-tree/)** - Browse your project structure in Warp's sidebar and open files directly. +* **[Code editor](/code/code-editor/)** - Edit files with syntax highlighting, LSP support, and find-and-replace without leaving Warp. +* **[Agent profiles and permissions](/agent-platform/capabilities/agent-profiles-permissions/)** - Configure how much autonomy the agent has when working with your code. diff --git a/src/content/docs/agent-platform/capabilities/computer-use.mdx b/src/content/docs/agent-platform/capabilities/computer-use.mdx new file mode 100644 index 0000000..8592ff1 --- /dev/null +++ b/src/content/docs/agent-platform/capabilities/computer-use.mdx @@ -0,0 +1,141 @@ +--- +title: Computer Use +description: >- + Let agents interact with desktop GUIs in sandboxed cloud environments for + automated UI testing and validation. +--- + +Computer Use is an experimental feature that enables Warp's agents to interact with desktop environments. The agent can see what's displayed on screen, click and drag, type text, use keyboard shortcuts, and perform other GUI interactions—all within a secure, isolated sandbox. + +A key use case is **testing UI changes** with a self-contained feedback loop, where the agent can verify that your code changes produce the expected visual and behavioral results without requiring manual testing. + +## Overview + +With Computer Use, agents can: + +* **Take screenshots** - Capture and analyze the current display +* **Interact with applications** - Click buttons, fill forms, navigate interfaces +* **Type and control keyboard** - Enter text and use keyboard shortcuts +* **Automate testing workflows** - Test UI changes end-to-end without manual intervention +* **Work with browser-based interfaces** - Test web apps and navigate the web + +Computer Use is only available in Warp's sandboxed cloud environments, not in local interactive terminal sessions. + +--- + +## Enabling Computer Use + +Computer Use is **opt-in** and disabled by default. You can enable it through several entry points: + +### Warp app settings + +To enable Computer Use for [Cloud Agents](/agent-platform/cloud-agents/overview/), navigate to **Settings** > **Agents** > **Warp Agent** > **Experimental** > **Computer use in Cloud Agents** and toggle to enable. + +### CLI + +When running agents in the cloud via the [CLI](/reference/cli/), use flags to control Computer Use per run: + +```bash +oz agent run-cloud --computer-use --prompt "<task>" +oz agent run-cloud --no-computer-use --prompt "<task>" +``` + +### API + +When calling the Warp API to create agent runs, include the `computer_use_enabled` field in your request: + +```json +{ + "prompt": "Build a button component that matches this design, then test it in the browser", + "computer_use_enabled": true, + "environment_id": "optional-environment-id" +} +``` + +For full API documentation, see the [Oz API & SDK](/reference/api-and-sdk/) reference. + +### Web App + +In the Warp web app, you can enable or disable Computer Use for: + +* **New agent runs** - Configure Computer Use when starting a new agent run from the web app +* **Scheduled agent runs** - Enable Computer Use for scheduled agents managed from the web app +* **Integrations** - Configure Computer Use for Slack, Linear, and other integration-triggered agents + +--- + +## How Computer Use works + +### Setup and requirements + +Computer Use runs in a containerized sandbox, allowing headless cloud environments to render and interact with graphical applications. The sandbox is fully isolated—it does not have access to your local machine, credentials, or sensitive data outside the sandbox environment. + +Your cloud environment must include any applications you want the agent to control. For example, to test a web app in a browser, install Chrome or Firefox in your [environment configuration](/agent-platform/cloud-agents/environments/). + +### Model selection + +Computer Use supports multiple Anthropic Claude models, including Claude 4.5 Sonnet, Claude 4.5 Opus, Claude 4.5 Haiku, Claude 4.6 Sonnet, and Claude 4.6 Opus. Warp uses an auto model selector to choose the best-suited model for each Computer Use task. + +--- + +## Security considerations + +Computer Use is an experimental feature with unique security considerations. These risks are heightened when interacting with the internet. + +To minimize risks when using Computer Use: + +1. **Avoid sensitive data** - Do not pass API keys, authentication tokens, or personal information to agents using Computer Use +2. **Limit internet access** - If your environment has internet access, consider restricting to an allowlist of known-safe domains +3. **Require human confirmation** - For tasks with real-world consequences (e.g., financial transactions, accepting legal terms), ask a human to confirm before the agent proceeds +4. **Review agent actions** - Regularly review what agents are doing on your behalf, especially when testing new workflows + +--- + +## Example workflows + +### Testing UI changes + +Verify that code changes produce the expected visual results and behavior: + +* **Build from mockups** - Receive a Figma design or mockup image, build the UI, and test it matches +* **Visual regression testing** - After code changes, verify UI renders correctly +* **Form and interaction testing** - Test form submissions, validation, error handling +* **Responsive design validation** - Test layout on different screen sizes + +**Example: Testing a React component** + +1. You ask the agent: "Build a React button component that matches this design, then test it" +2. Agent takes a screenshot to see the current state +3. Agent opens your dev server in a browser +4. Agent navigates to the component, verifies it renders correctly +5. Agent tests interactions (hover, click) and reports back + +**Example: Testing a web form** + +1. You provide a form design and ask the agent to build and test it +2. Agent renders your form in the browser +3. Agent fills fields with valid and invalid data +4. Agent verifies validation messages and submission behavior +5. Agent reports which fields worked correctly and which need adjustment + +**Example: Verifying UI responsiveness** + +1. You ask the agent to test your app on different screen sizes +2. Agent resizes the browser window to mobile, tablet, and desktop widths +3. Agent takes screenshots at each size and verifies layout is correct +4. Agent reports any responsive design issues + +### Browsing and web interaction + +Computer Use can also help with general web tasks: + +* Browse websites and interact with web interfaces +* Fill out and submit web forms +* Navigate multi-step workflows in web applications + +--- + +## Related capabilities + +* [Images as Context](/agent-platform/local-agents/agent-context/images-as-context/) - Pass design mockups and screenshots as context +* [Full Terminal Use](/agent-platform/capabilities/full-terminal-use/) - Let agents drive interactive terminal apps, see live output, and run commands diff --git a/src/content/docs/agent-platform/capabilities/full-terminal-use.mdx b/src/content/docs/agent-platform/capabilities/full-terminal-use.mdx new file mode 100644 index 0000000..d230f28 --- /dev/null +++ b/src/content/docs/agent-platform/capabilities/full-terminal-use.mdx @@ -0,0 +1,198 @@ +--- +title: Full Terminal Use +description: >- + Full Terminal Use means Warp's agents can interact with active terminal apps + to monitor live output and run commands. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +Full Terminal Use lets Warp's agent operate directly inside interactive terminal applications, such as database shells, debuggers, text editors, long-running servers, and more. + +The agent can see the live terminal buffer (terminal state), write to the PTY to run commands, respond to prompts, and continue working inside the running process while you stay in control. + +<VideoEmbed url="https://youtu.be/gBdehHrtb94?si=-vvl4ipGwwoWxEJq" /> + +## Overview + +With Full Terminal Use, Warp’s agent can attach to interactive tools like `psql`, `vim`, `python`, `gdb`, `top`, or your dev server, read the terminal output as it changes, and interact with the application as if you were typing. + +You can either ask the agent to start an interactive program, or you can start it yourself and then tag the agent in once the tool is already running. In both cases, the agent sees the same terminal buffer (and PTY session) you do and can act on it. + +## How Full Terminal Use works + +#### Start an interactive command + +You can either ask the agent to run an interactive command, or start one manually and then tag the agent in: + +* **Ask the agent to start an interactive tool** + * Example: + * “Open a Postgres shell and help me inspect the orders table.” + * “Start the dev server and debug this 500 error.” +* **Or start the command yourself, then tag the agent in** + * Example: + * If you’ve already launched an interactive tool (for example `psql` or `npm run dev`), you can bring the agent into the running session using the "Use Agent" button in the terminal footer or via `CMD + I` . + + ![Option to tag the agent into a running command.](../../../../assets/agent-platform/full-terminal-use-tag-hint.png) + * Once the agent is tagged in, you can follow up with natural-language requests such as: + + “Watch this process and help debug the error on the /session endpoint.” + * Warp then attaches the agent to the active PTY so it can see the current terminal buffer and propose actions inside the session. + +<VideoEmbed url="https://www.loom.com/share/bcedc521071a4b6a9bbcf74b5156f903" title="Tagging in the agent." /> + +![Running a build command.](../../../../assets/agent-platform/full-terminal-use-build.png) + +![Tagging in the Agent to monitor the dev server.](../../../../assets/agent-platform/full-terminal-use-dev-monitor.png) + +Warp attaches the agent to the running command so it can see and control the terminal buffer. + +#### Agents propose actions inside the session + +Once attached, you can continue using natural language and the agent turns your requests into concrete terminal actions. For example, in a Postgres shell: + +* You: “Show me all the tables and describe the orders table.” +* Agent: proposes running commands like: `\dt` --> `\d+ orders` + +In the UI, you’ll see a request to: + +* Run a specific command +* Optionally enable auto-approval for similar commands in this session + +#### Switching control between user and the agent + +You can swap control at any time. + +**Take over** + +* Use the Takeover control to stop the agent from typing or performing any actions. +* The shell stays open, and you can type directly into the same session. + +![Option to take over from agent in the footer.](../../../../assets/agent-platform/full-terminal-use-takeover.png) + +**Hand back control** + +* When you’re ready for the agent to continue, click the control again. +* The agent resumes where you left off, with full access to the current terminal state. + +![Option to hand-off to the agent in the conversation footer.](../../../../assets/agent-platform/full-terminal-use-handoff.png) + +This makes it easy to: + +* Let the agent do mechanical work (paging output, trying variants of a command) +* Step in for delicate or security-sensitive actions +* Then let the agent continue once the critical step is done + +#### Long-running commands in terminal vs agent view + +The behavior differs based on where you start the long-running command: + +<Tabs> + <TabItem label="From terminal view"> + 1. Run an interactive command (e.g., `python`, `psql`) + 2. Press `⌘↩` (macOS) or `Ctrl+Shift+Enter` (Windows/Linux), or use `⌘I` (macOS) / `Ctrl+I` (Windows/Linux), to tag in the agent + 3. The input switches to Agent Mode with full controls + 4. When you exit, an agent conversation block appears in your terminal blocklist + 5. Click the block to reopen the full conversation with your LRC interaction context + </TabItem> + <TabItem label="From agent view"> + 1. The agent runs an interactive command as part of your conversation + 2. Use `⌘↩` (macOS) or `Ctrl+Shift+Enter` (Windows/Linux) to tag in if the agent isn't already interacting + 3. The UI stays the same since you're already in agent view + 4. When you exit, the interaction remains part of your conversation. No separate block is created in the terminal blocklist + 5. Commands run in agent view are automatically included as context + </TabItem> +</Tabs> + +:::note +You can also use `CMD + I` (macOS) or `CTRL + I` (Windows/Linux) to toggle agent control in either view. +::: + +#### Showing and hiding agent responses + +Warp gives you control over how much agent output appears in Full Terminal Use. + +**Toggle visibility** + +Use the `Hide responses` or `Show responses` button or `CMD + G` in the interactive command footer to switch between showing all agent output or hiding it from the terminal view. + +Note that this only affects the agent's messages and proposals; your terminal state and command output remain unchanged. + +**Behavior when hidden** + +* When agent responses are hidden, your own agent requests automatically dismiss after **4 seconds** to keep the terminal clear. +* You can also manually dismiss any user query at any time by hovering over it and clicking the X. + +<VideoEmbed url="https://www.loom.com/share/c639fb4ab33343a39037b2083c66858a" /> + +--- + +### Configuring agent permissions and autonomy + +You control how much autonomy the agent has when interacting with the terminal. + +#### Session-level approvals + +Each time the agent wants to take an action inside an interactive shell, you’ll see the agent’s reasoning, a brief explanation, and the proposed command. From there you can: + +* Allow the command once (for example by approving it or pressing `ENTER`). +* Turn on auto-approval for similar commands in this session (for example with `CMD + SHIFT + I`). +* Refine the request with `CTRL + C`, which clears the proposed action and lets you follow up with a different query. +* Take over manually with `CMD + I`, which stops the agent from issuing any further PTY writes until you hand control back. + +![Allow, Refine, or Take over an agent response.](../../../../assets/agent-platform/allow-refine-takeover.png) + +![Ability to accept or auto-approve future interactions.](../../../../assets/agent-platform/full-terminal-use-options-2.png) + +This lets you tighten or loosen control for the current task: + +* For exploratory work, use **Always allow** to reduce friction. +* For production systems or sensitive operations, use **Allow once** and review each step. + +#### Global permission settings + +You can configure global defaults from your [Agent Profiles & Permissions](/agent-platform/capabilities/agent-profiles-permissions/) settings: + +* **Ask on first write**: The first write to a shell process requires approval. After that, all subsequent writes for that specific process/command will be approved. +* **Always ask**: Every write to the shell process from the agent requires your explicit approval. +* **Always allow**: The agent can write to the shell process without prompting you each time. + +These settings apply to every session that uses Full Terminal Use. You can still override them on a per-session basis when prompted. For example, you can enable **auto-approval** for similar commands in the current session using the fast-forward control, or switch to a **different AI profile** with its own permission settings for that conversation. + +:::note +**Note**: All [Secret Redaction](/support-and-community/privacy-and-security/secret-redaction/) features still apply during Full Terminal Use, so sensitive values in your environment or output remain protected. +::: + +### Credits usage + +All AI interactions from Full Terminal Use consume [credits](/support-and-community/plans-and-billing/credits/), including understanding your natural language requests. + +Credits are consumed in a similar way as other Oz actions that use the same model and a similar context size. + +**Interactive sessions can consume more credits if:** + +* The agent runs many commands in an interactive shell on your behalf. +* There is a significant amount of terminal output to read and summarize. + +**To manage credit usage:** + +* Use tighter scopes: + * “Describe just the orders table.” instead of “Explain the entire database.” +* Pause autonomy for high-volume tasks with copious terminal output: + * Take over manual control when running large batches or long logs. +* Use stricter permissions: + * Set global permissions to "Ask on first write" or "Always ask", then approve only what you need. + +:::note +To learn more about what goes into a credit and how to get more value from AI usage in Warp, see: [_Getting the most out of credits in Warp_](https://www.warp.dev/blog/warp-ai-requests). +::: + +## Example workflows + +Here’s a demo from one of our engineers, Maggie, that walks through a couple of Full Terminal Use examples. + +<VideoEmbed url="https://www.loom.com/share/d47ee09153df417983df65a339a9d6f2" /> + +Below are some common interactive tools where Full Terminal Use is particularly useful: database shells (Postgres, MySQL, SQLite), debuggers such as gdb, language-specific REPLs like python or node, text editors and file explorers, and long-running dev servers or monitoring tools such as top and htop. + +<table><thead><tr><th width="158.5418701171875">Tool</th><th width="326.64208984375">Example tasks</th><th>Agents can...</th></tr></thead><tbody><tr><td><strong>Database shells (REPLs)</strong><br /><br />e.g. <code>psql</code>, <code>mysql</code>, <code>sqlite</code>, etc.</td><td><ul><li>“List all tables and describe the users and orders tables.”</li><li>“Create a new table to store archived user sessions.”</li><li>“Show me all rows in orders from the last 30 days, grouped by status.”</li><li>“Generate and run a query that finds the top 10 customers by revenue.”</li></ul></td><td><ul><li>Navigate <code>\d</code>, <code>\dt</code>, <code>DESCRIBE</code>, etc.</li><li>Write and execute SQL queries</li><li>Summarize results in plain language</li></ul></td></tr><tr><td><strong>Text editors</strong><br /><br />e.g. <code>vim</code>, <code>nano</code>, etc.</td><td><ul><li>“Open this file in vim and add a Markdown header and a boilerplate section.”</li><li>“Insert a docstring above this function explaining what it does.”</li><li>“Generate a CSS utility class block and insert it in this file.”</li></ul></td><td><ul><li>Navigate within the editor using keystrokes</li><li>Insert, edit, and delete text</li><li>Save and quit when done</li></ul></td></tr><tr><td><strong>Python REPLs</strong><br /><br />e.g. <code>python</code>, <code>ipython</code></td><td><ul><li>“Start a Python REPL and define a function that calculates a moving average.”</li><li>“Write a unit test for this function and run it.”</li><li>“Plot x from 0 to 10 and y = sin(x).”</li></ul></td><td><ul><li>Import modules</li><li>Define functions and classes</li><li>Run tests and small scripts</li><li>Print or summarize results back to you</li></ul></td></tr><tr><td><strong>Debuggers</strong><br /><br />e.g. <code>gdb</code>, <code>lldb</code>, language-specific debuggers</td><td><ul><li>“Start gdb for this binary and set a breakpoint on <code>handle_request</code>.”</li><li>“Run until the breakpoint, then show the stack and local variables.”</li><li>“Inspect this pointer and tell me if it looks invalid.”</li></ul></td><td><ul><li>Issue debugger commands (break, run, next, continue, bt, etc.)</li><li>Walk through execution step by step</li><li>Summarize relevant state so you don’t have to remember every command</li></ul></td></tr><tr><td><strong>Long-running servers and services</strong><br /><br />e.g. <code>npm run dev</code>, <code>uvicorn</code>, Rails servers, etc</td><td><ul><li>“Run the dev server and debug the internal server error on /session.”</li><li>“Send a sample request to this endpoint and explain the failure.”</li><li>“Kill the server once you identify the error and propose a code diff.”</li></ul></td><td><ul><li>Watch server logs in real time</li><li>Notice new errors as they appear</li><li>Stop the server when appropriate</li><li>Propose code changes (for example, via a diff) based on what it observes</li></ul></td></tr><tr><td><strong>Version control workflows</strong><br /><br />e.g. <code>git rebase -i</code>, complex git commands</td><td><ul><li>“Interactively rebase master onto <code>feature-branch</code> to squash these commits into one.”</li><li>“Resolve these merge conflicts and ensure tests pass.”</li></ul></td><td><ul><li>Navigate interactive rebase prompts</li><li>Edit commit messages</li><li>Apply conflict resolutions you approve</li></ul></td></tr><tr><td><strong>Cloud provider CLIs</strong><br /><br />e.g. <code>gcloud</code>, <code>aws</code>, <code>az</code>, etc.</td><td><ul><li>“Use gcloud to create a new Kubernetes cluster with these settings.”</li><li>“Provision a new RDS instance for staging and show me the connection details.”</li></ul></td><td><ul><li>Walk through multi-step CLI workflows</li><li>Handle prompts and confirmations</li><li>Summarize the resulting resources</li></ul></td></tr></tbody></table> diff --git a/src/content/docs/agent-platform/capabilities/index.mdx b/src/content/docs/agent-platform/capabilities/index.mdx new file mode 100644 index 0000000..75644d3 --- /dev/null +++ b/src/content/docs/agent-platform/capabilities/index.mdx @@ -0,0 +1,29 @@ +--- +title: Capabilities +description: >- + Core capabilities and configuration options that shape how agents behave, + what context they have access to, and how they execute tasks. +--- + +These capabilities are the foundational building blocks that define how agents operate. These include the context sources agents can access, the rules that guide their behavior, and the tools they can use. + +Understanding these capabilities helps you get the most out of agents by configuring them to match your workflows and preferences. + +## Capabilities in this section + +* [Slash Commands](/agent-platform/capabilities/slash-commands/) - Quick actions and saved prompts accessible by typing `/` in Agent Mode. +* [Skills](/agent-platform/capabilities/skills/) - Reusable, scoped instructions that teach agents how to perform specific tasks in your codebase. +* [Planning](/agent-platform/capabilities/planning/) - Turn agent requests into organized, editable plans that execute step-by-step with full visibility. +* [Task Lists](/agent-platform/capabilities/task-lists/) - Track complex workflows with automatic task lists that update progress in real time. +* [Model Choice](/agent-platform/capabilities/model-choice/) - Pick your preferred LLM from a curated set of top models, or let Warp choose the optimal one. +* [Rules](/agent-platform/capabilities/rules/) - Define global and project-level guidelines that shape agent behavior and responses. +* [Full Terminal Use](/agent-platform/capabilities/full-terminal-use/) - Let the agent drive interactive terminal apps, seeing live output and running commands. +* [Computer Use](/agent-platform/capabilities/computer-use/) - Let agents interact with desktop environments by taking screenshots, clicking, typing, and controlling the GUI. +* [MCP](/agent-platform/capabilities/mcp/) - Connect external data sources and tools to Warp's agents via the Model Context Protocol. +* [Codebase Context](/agent-platform/capabilities/codebase-context/) - Let agents understand your codebase through semantic indexing of your Git-tracked files. +* [Agent Profiles & Permissions](/agent-platform/capabilities/agent-profiles-permissions/) - Control what permissions and autonomy agents have to run commands and apply changes. +* [Web Search](/agent-platform/capabilities/web-search/) - Allow agents to search the web for up-to-date information. + +## Related + +For hands-on agent interactions, see [Local Agents](/agent-platform/local-agents/overview/). diff --git a/src/content/docs/agent-platform/capabilities/mcp.mdx b/src/content/docs/agent-platform/capabilities/mcp.mdx new file mode 100644 index 0000000..fb1f827 --- /dev/null +++ b/src/content/docs/agent-platform/capabilities/mcp.mdx @@ -0,0 +1,457 @@ +--- +title: Model Context Protocol (MCP) +description: >- + Configure MCP servers in the Warp desktop app to extend local agents with + custom tools and data sources through a standardized interface. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +MCP servers extend Warp's [local agents](/agent-platform/local-agents/interacting-with-agents/) in a modular, flexible way by exposing custom tools or data sources through a standardized interface — essentially acting as plugins for Warp. Warp supports a variety of connection protocols, including Streamable HTTPS and SSE, along with custom headers and environment variables. + +MCP is an open source protocol. Check out the official [MCP documentation](https://modelcontextprotocol.io/introduction) for more detailed information on how this protocol is engineered. + +:::note +This page covers MCP servers for local agents in the Warp desktop app. If you're using cloud agents, see [MCP Servers for cloud agents](/agent-platform/cloud-agents/mcp/). +::: + +### How to access MCP Server settings + +You can navigate to the MCP servers page in any of the following ways: + +* From the [Settings Page](warp://settings/mcp): **Settings** > **Agents** > **MCP servers** +* From [Warp Drive](/knowledge-and-collaboration/warp-drive/): under **Personal** > **MCP Servers** +* From the [Command Palette](/terminal/command-palette/): search for `Open MCP Servers` +* From the Warp app: **Settings** > **Agents** > **Warp Agent** > **Manage MCP servers** + +This will show a list of all configured MCP servers, including which are currently running. If you close Warp with an MCP server running, it will run again on next start of Warp. MCP servers that are stopped will remain so on next launch of Warp. + +![MCP servers page](../../../../assets/agent-platform/mcp-servers-list.png) + +### Adding an MCP Server + +To add a new MCP server, you can click the **+ Add** button. Configurations from most MCP Clients can be directly copied and pasted. + +MCP server types you can add: + +<Tabs> + <TabItem label="CLI Server (Command)"> + Provide a startup command. Warp will launch this command when starting up and shut it down on exit. + + ![Adding a CLI MCP Server (Command)](../../../../assets/agent-platform/mcp-servers-add-cli.png) + + :::note + Always set `working_directory` explicitly when your MCP server command or args include relative paths. This ensures consistent and predictable behavior across machines and sessions. + ::: + + **CLI Server (Command) MCP Configuration Properties** + + | Property | Type | Required | Description | + | ------------------- | --------- | -------- | ----------------------------------------------------------------------------------- | + | `command` | string | Yes | The executable to launch (e.g., `npx`). | + | `args` | string\[] | Yes | Array of command-line arguments passed to `command` (e.g., module name, paths). | + | `env` | object | No | Key-value object of environment variables (e.g., API Tokens). | + | `working_directory` | string | No | Working directory path where the command is run, used for resolving relative paths. | + </TabItem> + <TabItem label="Streamable HTTP or SSE Server (URL)"> + Provide a URL where Warp can reach an already-running MCP server that supports Server-Sent Events. + + ![Adding an SSE MCP Server (URL)](../../../../assets/agent-platform/mcp-servers-add-sse.png) + + **Streamable HTTP or SSE Server (URL) MCP Configuration Properties** + + | Property | Type | Required | Description | + | --------- | ------ | -------- | ----------------------------------------------------------------- | + | `url` | string | Yes | The HTTP endpoint URL to connect to via Server-Sent Events (SSE). | + | `headers` | object | No | Key-value object of header variables (e.g., Authorization). | + </TabItem> +</Tabs> + +### Adding multiple MCP servers + +Warp supports configuring **multiple MCP servers** using a JSON snippet. Each entry under `mcpServers` is keyed by a unique name (`filesystem`, `github`, `notes`, etc). All servers defined in the example are added automatically — no manual setup required. + +To add a multiple MCP servers, you can click the **+ Add** button then paste in a JSON snippet like the example below: + +```json +{ + "mcpServers": { + "filesystem": { + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/files"] + }, + "notes": { + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-notes", "--notes-dir", "/Users/you/Documents/notes"] + }, + "externalDocs": { + "url": "http://localhost:4000/mcp/stream", + "headers": { + "my-header": "my-header-value" + } + } + } +} +``` + +### File-based MCP servers + +Warp detects MCP server configurations managed by supported third-party agents and can automatically spawn them alongside your manually configured servers. + +To enable, go to **Settings** > **Agents** > **MCP servers** and toggle **File-based MCP Servers** on. + +![File-based MCP Servers toggle](/assets/agent-platform/file-based-mcp-toggle.gif) + +When enabled: + +* **Global/user-scoped servers** - spawned on Warp startup and available in any session. +* **Project-scoped servers** - spawned when you enter a repo containing a supported config file, and available within that project only. + +Supported providers: + +* **Claude Code** - reads user-scoped config (`~/.claude.json`) and project-scoped config (`.mcp.json` at project root). See [user scope](https://code.claude.com/docs/en/mcp#user-scope) and [project scope](https://code.claude.com/docs/en/mcp#project-scope) in the Claude Code docs. +* **Codex** - reads global config (`~/.codex/config.toml`) and project-scoped config (`.codex/config.toml` at project root). See [Codex MCP docs](https://developers.openai.com/codex/mcp/#connect-codex-to-an-mcp-server). + +:::note +File-based servers that require OAuth show an authentication modal on their first spawn. Credentials are saved for future spawns, the same as manually configured MCP servers. +::: + +### Managing MCP servers + +After MCP servers are registered in Warp, you can **Start** or **Stop** them from the MCP servers page. Each running server will have a list of available tools and resources. + +You can rename and edit a server's name, as well as delete the server. If you are a part of a Team, you can also share a MCP with your teammates. + +### Sharing MCP servers + +MCP servers can be shared with your teammates by clicking the share icon. When sharing, sensitive values in the `env` configuration will be automatically scrubbed and replaced with variables. + +![Sharing a MCP Server](../../../../assets/agent-platform/mcp-servers-share.png) + +Your teammates can find shared MCP servers under the `Shared` section of their MCP settings. When your teammates install your server configuration, they will be prompted to enter any scrubbed `env` values. + +Warp also provides out-of-the-box MCP servers that can be installed by anyone. These can be found under the `Shared` section of your MCP settings. + +### Authentication in MCP servers + +Most MCP servers require authentication to connect to external services. Warp supports the following methods: + +* **Environment variables**: pass an API key or access token via the server's environment variables. +* **OAuth login (one-click installation)**: simplifies configuration by handling authentication through your browser. Warp stores credentials securely on your device and reuses them for future sessions. Re-authentication is required when opening Warp on a new machine. + * Starting a server without existing credentials automatically opens a browser-based authentication flow. + * Credentials can be revoked at any time from the MCP Servers pane in Warp. +* **Custom Headers**: pass an Authentication Bearer token via the headers variable. + +### Debugging MCP + +If you're having trouble with an MCP server, you can check the logs for any errors or messages to help you diagnose the problem by clicking the `View Logs` button on a server from the MCP servers page. + +:::caution +If you choose to share your MCP server logs with anybody, **make sure to remove any sensitive information before sharing**, as they may contain API keys. + +Many SSE based MCP servers will state that your URL should be treated like a password, and can be used with no additional authentication. +::: + +:::note +Tip: We've noticed that some models often work better with MCP servers than others. If you're having trouble calling or using an MCP server, try using a different model. +::: + +#### Debugging MCP Authentication issues + +In some cases you may need to reset the auth token for some MCP servers. To do this delete the local MCP auth files by running the following: `rm -rf ~/.mcp-auth` + +:::caution +Note this will delete all your MCP auth tokens stored locally so you will need to login and re-authenticate. +::: + +If the above doesn't help and you need to reset or change authentication, you may need to switch to a CLI-based MCP server configuration and provide the token via environment variables. See [Sentry CLI MCP Example](/agent-platform/capabilities/mcp/#sentry). + +### Where MCP logs are stored + +Warp saves the MCP logs locally on your computer. You can open the files directly and inspect the full contents in the following location: + +<Tabs> + <TabItem label="macOS"> + ```bash + cd "$HOME/Library/Group Containers/2BBY89MBSN.dev.warp/Library/Application Support/dev.warp.Warp-Stable/mcp" + ``` + </TabItem> + <TabItem label="Windows"> + ```powershell + Set-Location $env:LOCALAPPDATA\warp\Warp\data\logs\mcp + ``` + </TabItem> + <TabItem label="Linux"> + ```bash + cd "${XDG_STATE_HOME:-$HOME/.local/state}/warp-terminal/mcp" + ``` + </TabItem> +</Tabs> + +## MCP server configuration examples + +Below are examples for popular Model Context Protocol (MCP) servers. + +* **CLI Server (Command)** — local `npx` or `docker` command based MCP servers. +* **Streamable HTTP or SSE Server (URL)** — remote or locally hosted MCP endpoints. + +### **Engineering & Ops** + +<Tabs> + <TabItem label="GitHub"> + [GitHub MCP Docs](https://github.com/github/github-mcp-server) + + **GitHub CLI Server (Command)** + + ```json + { + "GitHub": { + "command": "docker", + "args": ["run","-i","--rm","-e","GITHUB_PERSONAL_ACCESS_TOKEN","ghcr.io/github/github-mcp-server"], + "env": { + "GITHUB_PERSONAL_ACCESS_TOKEN": "<your_github_token>" + } + } + } + ``` + + **GitHub SSE Server (URL)** + + ```json + { + "GitHub": { + "url": "https://api.githubcopilot.com/mcp/" + } + } + ``` + </TabItem> + <TabItem label="Sentry"> + [Sentry MCP Docs](https://docs.sentry.io/product/sentry-mcp/) + + **Sentry CLI Server (Command)** + + ```json + { + "Sentry": { + "command": "npx", + "args": ["-y","mcp-remote@latest","https://mcp.sentry.dev/mcp"] + } + } + ``` + + **Sentry SSE Server (URL)** + + ```json + { + "Sentry": { + "url": "https://mcp.sentry.dev/sse" + } + } + ``` + </TabItem> + <TabItem label="Grafana"> + [Grafana MCP Docs](https://github.com/grafana/mcp-grafana) + + **Grafana CLI Server (Command)** + + ```json + { + "Grafana": { + "command": "docker", + "args": ["run","--rm","-i","-e","GRAFANA_URL","-e","GRAFANA_API_KEY","mcp/grafana","-t","stdio","-debug"], + "env": { + "GRAFANA_URL": "http://localhost:3000", + "GRAFANA_API_KEY": "<your_grafana_key>" + } + } + } + ``` + + **Grafana SSE Server (URL)** + + ```json + { + "Grafana": { + "url": "https://your-mcp-host.com/api/mcp/grafana/sse" + } + } + ``` + </TabItem> + <TabItem label="Linear"> + [Linear MCP Docs](https://linear.app/docs/mcp) + + **Linear CLI Server (Command)** + + ```json + { + "Linear": { + "command": "npx", + "args": ["-y","mcp-remote","https://mcp.linear.app/sse"] + } + } + ``` + + **Linear SSE Server (URL)** + + ```json + { + "Linear": { + "url": "https://mcp.linear.app/sse" + } + } + ``` + </TabItem> + <TabItem label="Chroma"> + **Chroma Package Search CLI Server (Command)** + + 1. Visit Chroma's [Package Search](http://trychroma.com/package-search) page. + 2. Click "Get API Key" to create or log into your Chroma account and issue an API key for Package Search. + 3. After issuing your API key, click the "Other" tab and copy your API key. + 4. Add the following to your Warp MCP config. Make sure to click "Start" on the server after adding. + + More info in [Chroma's Package Search MCP Docs](https://docs.trychroma.com/cloud/package-search/mcp) + + ```json + { + "package-search": { + "command": "npx", + "args": ["mcp-remote", "https://mcp.trychroma.com/package-search/v1", "--header", "x-chroma-token: ${X_CHROMA_TOKEN}"], + "env": { + "X_CHROMA_TOKEN": "<YOUR_CHROMA_API_KEY>" + } + } + } + ``` + </TabItem> +</Tabs> + +### **Design & Collaboration** + +<Tabs> + <TabItem label="Figma"> + **Figma Remote MCP Server (Recommended)** + + The official Figma remote MCP server supports OAuth for simple, one-click setup. + + 1. In Warp, go to **Warp Drive** > **MCP Servers** > **+ Add** and paste the configuration below. + 2. Warp will open a browser window to authenticate with Figma. + 3. After approving access, credentials are stored securely on your device. + + :::note + Note: A Figma account with [Dev Mode](https://www.figma.com/dev-mode/) enabled is required. + ::: + + ```json + { + "Figma": { + "url": "https://mcp.figma.com/mcp" + } + } + ``` + + **Figma Local MCP Server** + + 1. Enable the Official Figma MCP Server. [Figma MCP Docs](https://help.figma.com/hc/en-us/articles/32132100833559-Guide-to-the-Figma-MCP-server) + 2. Open the [Figma desktop app](https://www.figma.com/downloads/) and make sure you’ve [updated to the latest version](https://help.figma.com/hc/en-us/articles/5601429983767-Guide-to-the-Figma-desktop-app#h_01HE5QD60DG6FEEDTZVJYM82QW). + 3. Create or open a Figma Design file. + 4. In the upper-left corner, open the Figma menu. + 5. Under **Preferences**, select **Enable local MCP Server**. + 6. Enter the following configuration into **Warp** > **Warp Drive** > **MCP Servers** > **+ Add**. + + ```json + { + "Figma (Local)": { + "url": "http://127.0.0.1:3845/mcp" + } + } + ``` + </TabItem> + <TabItem label="Slack"> + [Slack MCP Docs](https://github.com/korotovsky/slack-mcp-server/) + + **Slack CLI Server (Command)** + + Enter the following configuration into **Warp** > **Warp Drive** > **MCP Servers** > **+ Add**. + + ```json + { + "Slack": { + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-slack"], + "env": { + "SLACK_BOT_TOKEN": "xoxb-<your-bot-token>", + "SLACK_APP_TOKEN": "xapp-<your-app-token>", + "SLACK_TEAM_ID": "T<your_workspace_id>", + "SLACK_CHANNEL_IDS": "<your_channel_id-1>, <your_channel_id-2>", + "MCP_MODE": "stdio" + } + } + } + ``` + + **Slack SSE Server (URL)** + + Enter the following configuration into **Warp** > **Warp Drive** > **MCP Servers** > **+ Add**. + + ```json + { + "Slack": { + "url": "https://your-mcp-host.com/api/mcp/slack/sse" + } + } + ``` + </TabItem> + <TabItem label="Atlassian"> + [Atlassian MCP Docs](https://support.atlassian.com/rovo/docs/setting-up-ides/) + + **Atlassian CLI Server (Command)** + + Enter the following configuration into **Warp** > **Warp Drive** > **MCP Servers** > **+ Add**. + + ```json + { + "Atlassian": { + "command": "npx", + "args": ["-y", "mcp-remote", "https://mcp.atlassian.com/v1/sse"] + } + } + ``` + </TabItem> + <TabItem label="Notion"> + [Notion MCP Docs](https://developers.notion.com/docs/mcp) + + **Notion CLI Server (Command)** + + Enter the following configuration into **Warp** > **Warp Drive** > **MCP Servers** > **+ Add**. + + ```json + { + "Notion": { + "command": "npx", + "args": ["-y", "mcp-remote", "https://mcp.notion.com/mcp"] + } + } + ``` + + **Notion SSE Server (URL)** + + Enter the following configuration into **Warp** > **Warp Drive** > **MCP Servers** > **+ Add**. + + ```json + { + "Notion": { + "url": "https://mcp.notion.com/sse" + } + } + ``` + </TabItem> +</Tabs> + +### MCP server demos + +[Warp Guides](/guides/) hosts a collection of demos and walkthroughs showing how MCP servers can extend your workflows. Each example highlights practical use cases you can try today: + +* [**GitHub**](/guides/external-tools/github-mcp-summarizing-open-prs-and-creating-gh-issues/) — access repositories, issues, and pull requests through MCP. +* [**Sentry**](/guides/external-tools/sentry-mcp-fix-sentry-error-in-empower-website/) — surface error monitoring and alerts as agent-usable data. +* [**Linear**](/guides/external-tools/linear-mcp-retrieve-issue-data/) — integrate project management tasks and tickets. +* [**Puppeteer**](/guides/external-tools/puppeteer-mcp-scraping-amazon-web-reviews/) — run automated browser workflows via MCP. +* [**Context7**](/guides/external-tools/context7-mcp-update-astro-project-with-best-practices/) — experiment with external data integrations. diff --git a/src/content/docs/agent-platform/capabilities/model-choice.mdx b/src/content/docs/agent-platform/capabilities/model-choice.mdx new file mode 100644 index 0000000..59e8c36 --- /dev/null +++ b/src/content/docs/agent-platform/capabilities/model-choice.mdx @@ -0,0 +1,129 @@ +--- +title: Model choice +description: >- + Choose from a curated set of top LLMs for Warp's Agents (or let Warp + auto-select the best model). +--- + +## Available models + +Warp lets you choose from a curated set of Large Language Models (LLMs) to power your Agentic Development Environment. + +**Warp supports the following models.** + +The `model_id` values shown below can be used when configuring models via the [Oz Platform](/agent-platform/cloud-agents/platform/) or [CLI](/reference/cli/). + +### Auto models + +| Model | `model_id` | Description | +| --- | --- | --- | +| Auto (Responsive) | `auto` | Selects the highest-quality, fastest available model. May consume credits more quickly. | +| Auto (Cost-efficient) | `auto-efficient` | Optimizes for lower credit consumption while maintaining strong output quality. | +| Auto (Genius) | `auto-genius` | Adapts to task complexity and selects Warp's most capable model when it's worth it. Best for deep debugging, architecture decisions, and `/plan` sessions. | +| Auto (Open-weights) | `auto-open` | Routes between the best open-source models available in Warp. Optimizes for low cost and fast speed using open-weights models. | + +All Auto models perform well across all agent workflows and are ideal if you prefer Warp to manage model selection dynamically. + +#### OpenAI + +| Model | `model_id` | Reasoning Level | +| --- | --- | --- | +| GPT-5.5 | `gpt-5-5-low` | Low | +| GPT-5.5 | `gpt-5-5-medium` | Medium | +| GPT-5.5 | `gpt-5-5-high` | High | +| GPT-5.5 | `gpt-5-5-xhigh` | Extra High | +| GPT-5.4 | `gpt-5-4-low` | Low | +| GPT-5.4 | `gpt-5-4-medium` | Medium | +| GPT-5.4 | `gpt-5-4-high` | High | +| GPT-5.4 | `gpt-5-4-xhigh` | Extra High | +| GPT-5.3 Codex | `gpt-5-3-codex-low` | Low | +| GPT-5.3 Codex | `gpt-5-3-codex-medium` | Medium | +| GPT-5.3 Codex | `gpt-5-3-codex-high` | High | +| GPT-5.3 Codex | `gpt-5-3-codex-xhigh` | Extra High | +| GPT-5.2 Codex | `gpt-5-2-codex-low` | Low | +| GPT-5.2 Codex | `gpt-5-2-codex-medium` | Medium | +| GPT-5.2 Codex | `gpt-5-2-codex-high` | High | +| GPT-5.2 Codex | `gpt-5-2-codex-xhigh` | Extra High | +| GPT-5.2 | `gpt-5-2-low` | Low | +| GPT-5.2 | `gpt-5-2-medium` | Medium | +| GPT-5.2 | `gpt-5-2-high` | High | +| GPT-5.2 | `gpt-5-2-xhigh` | Extra High | + +#### Anthropic + +| Model | `model_id` | Variant | +| --- | --- | --- | +| Claude Opus 4.7 | `claude-4-7-opus-xhigh` | Default effort | +| Claude Opus 4.7 | `claude-4-7-opus-high` | High effort | +| Claude Opus 4.7 | `claude-4-7-opus-max` | Max effort | +| Claude Opus 4.6 | `claude-4-6-opus-high` | Default effort | +| Claude Opus 4.6 | `claude-4-6-opus-max` | Max effort | +| Claude Sonnet 4.6 | `claude-4-6-sonnet-high` | Default effort | +| Claude Sonnet 4.6 | `claude-4-6-sonnet-max` | Max effort | +| Claude Opus 4.5 | `claude-4-5-opus` | Thinking off | +| Claude Opus 4.5 | `claude-4-5-opus-thinking` | Thinking on | +| Claude Sonnet 4.5 | `claude-4-5-sonnet` | Thinking off | +| Claude Sonnet 4.5 | `claude-4-5-sonnet-thinking` | Thinking on | +| Claude Haiku 4.5 | `claude-4-5-haiku` | — | + +#### Google + +| Model | `model_id` | +| --- | --- | +| Gemini 3.1 Pro | `gemini-3.1-pro` | + +#### Hosted models (via [Fireworks AI](https://fireworks.ai)) + +Warp also supports leading open source models hosted via Fireworks AI, so you can run them from inside Warp without setting up your own inference infrastructure. + +| Model | `model_id` | +| --- | --- | +| GLM 5 | `glm-5-fireworks` | +| GLM 5.1 | `glm-5.1-fireworks` | +| Kimi K2.5 | `kimi-k25-fireworks` | +| Kimi K2.6 | `kimi-k26-fireworks` | +| Minimax 2.7 | `minimax-2.7-fireworks` | +| Qwen 3.6 Plus | `qwen-3.6-plus-fireworks` | + +### How to change models + +You can use the model picker in your prompt input to quickly switch between models. The currently active model appears directly in the input editor. + +![Model selector dropdown showing available models with Intelligence, Speed, and Cost benchmarks](../../../../assets/agent-platform/model-selector-dropdown.png) + +To change models, click the displayed model name (for example, _Claude Sonnet 4.5_) to open a dropdown with all supported options. Your selection will automatically persist for future prompts. + +### Model fallback + +Warp uses a model fallback system to ensure uninterrupted service if your selected model becomes temporarily unavailable due to provider outages or capacity issues. + +**How it works:** + +* If your selected model isn't available, Warp automatically uses a fallback model from a predefined chain to continue your conversation without errors. +* As soon as your originally selected model becomes available again, Warp automatically switches back to it. +* The fallback model is selected to provide comparable quality and capabilities to your original choice. + +### Configuring models per Agent Profile + +You can configure the base model for each [Agent Profile](/agent-platform/capabilities/agent-profiles-permissions/), alongside the Agent's autonomy, tool access, and other permissions. The base model is also used for [Planning](/agent-platform/capabilities/planning/). + +Edit your default profile or any other profile directly in **Settings** > **Agents** > **Profiles**. + +### Zero data retention policies + +Warp integrates with multiple Large Language Model (LLM) providers to power its AI-driven features. + +**These providers include, but are not limited to:** + +* OpenAI +* Anthropic +* Google +* xAI +* Fireworks AI + +Warp has executed **Zero Data Retention (ZDR)** agreements with these providers. This means that, by default across all plans: + +* LLM providers commit not to train their models on any customer-generated data processed through Warp’s services. +* LLM providers commit to delete inputs and outputs after generating the relevant output, within a fixed time period. + +Warp enforces these commitments through both technical measures and contractual safeguards with the LLM providers. diff --git a/src/content/docs/agent-platform/capabilities/planning.mdx b/src/content/docs/agent-platform/capabilities/planning.mdx new file mode 100644 index 0000000..2ee72d2 --- /dev/null +++ b/src/content/docs/agent-platform/capabilities/planning.mdx @@ -0,0 +1,86 @@ +--- +title: Planning +description: >- + Turn requests into structured, editable plans that agents execute + step-by-step with version control. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Warp has native planning functionality that helps you break down complex engineering tasks into structured, executable steps. Planning is tightly integrated with Warp's coding agent and provides a persistent plan editor, version history, selective execution, and deep links into your workspace. + +<VideoEmbed url="https://youtu.be/DawcFWyudV0?si=OzvuInMl8DoNR97R" /> + +--- + +### Creating a plan + +You can generate a plan using the `/plan` [slash command](/agent-platform/capabilities/slash-commands/) or by asking the agent in natural language. + +![Prompting the agent to create a plan using the slash command.](../../../../assets/agent-platform/plan-slash-command.png) + +The agent then creates a structured plan inside Warp’s native rich text editor, which is designed for long, multi-step workflows. The editor includes clean formatting, inline code blocks, and clickable file paths so you can open referenced files immediately in Warp (see below) or in your external editor. + +### Reviewing and editing + +Once a plan is generated, you can review it, reorganize steps, or refine details. You can edit the document manually or ask the agent to revise sections for you. + +![Plan editor in Warp.](../../../../assets/agent-platform/planning-main-view.png) + +Any update made by the agent **creates a new version**. Version history lets you compare past iterations and restore an older version if you want to revert your approach, preserving a clear decision trail as the plan evolves. + +![Access previous versions of your plan.](../../../../assets/agent-platform/agent-plans-versioning.png) + +### Executing a plan + +When you’re ready to start implementing, prompt the agent to run the plan. You can ask it to execute the full set of steps or only a specific section, such as “Implement phase 1 of the plan.” + +![Manually referencing the plan using @ to kickoff the plan.](../../../../assets/agent-platform/manually-trigger-plan.png) + +The agent applies changes incrementally and updates files as it proceeds. This makes it easy to validate early steps before moving forward, adjust the plan mid-run, or try alternative paths without committing to the full workflow. + +If you revise the plan while the agent is running, you can notify it directly; the agent will adjust its execution based on your updates. + +![Option to pass new plan to agent if plan changes during runtime.](../../../../assets/agent-platform/update-agent-mid-plan.png) + +### Monitoring progress + +While the agent is running, you can reopen the plan at any time by selecting **View plan** in the input. You can also follow each change in real time through the [Code Review](/code/code-review/) panel and add comments or guidance using [Interactive Code Review](/agent-platform/local-agents/interactive-code-review/). + +![Monitoring progress with the task list and plan view.](../../../../assets/agent-platform/agent-plans-tasks.png) + +This gives you clear oversight, helps confirm expected behavior, and lets you intervene quickly if something needs correction. + +### Saving and sharing + +Warp automatically saves all plans in the _Plans_ folder in [Warp Drive](/knowledge-and-collaboration/warp-drive/). You'll see a confirmation when your plan is synced. + +![Plans are automatically synced to Warp Drive.](../../../../assets/agent-platform/agent-plans-synced.png) + +You can export any plan as Markdown, check it into your repository, or share a link—useful for GitHub PRs, design reviews, or async collaboration. + +![Different ways to share a plan.](../../../../assets/agent-platform/export-notebooks.png) + +Because plans persist in Warp Drive, you can return to them later, reuse them for new work, or treat them as documentation for ongoing projects. This is also naturally passed to the agent as context. + +![Plans are accessible directly from the Warp Drive side panel.](../../../../assets/agent-platform/plans-in-warp-drive-side-panel.png) + +You can configure whether your plans will be automatically added and synced to Warp Drive in your [Agent Profiles & Permissions](/agent-platform/capabilities/agent-profiles-permissions/) under **Settings** > **Agents** > **Profiles**. + +![Toggle in Agent Profiles & Permissions to automatically sync agent-generated plans to Warp Drive.](../../../../assets/agent-platform/auto-sync-plans-1.png) + +### Using plans across conversations + +Plans are reusable across tasks and sessions. You can reference them in future prompts, continue where you left off, or build follow-up plans that rely on earlier work. + +The **@plans** command helps you quickly search for and reopen previously saved plans, making planning a consistent part of your development workflow rather than a one-off step. Learn more about attaching context using @ [here](/agent-platform/local-agents/agent-context/using-to-add-context/). + +![Searching for and reopening previously saved plans with the @plans command.](../../../../assets/agent-platform/@-reference-plans.png) + +--- + +## Next steps + +As the agent executes your plan, you'll review code changes and may want to scale work to the cloud. + +* **[Interactive Code Review](/agent-platform/local-agents/interactive-code-review/)** - Leave inline comments on agent-generated diffs and have the agent revise in one pass. +* **[Cloud Agents quickstart](/agent-platform/cloud-agents/quickstart/)** - Run agents in the cloud for longer tasks, background automation, or parallel work across repos. diff --git a/src/content/docs/agent-platform/capabilities/rules.mdx b/src/content/docs/agent-platform/capabilities/rules.mdx new file mode 100644 index 0000000..64f937d --- /dev/null +++ b/src/content/docs/agent-platform/capabilities/rules.mdx @@ -0,0 +1,122 @@ +--- +title: Rules +description: >- + Create reusable Global or Project Rules to ensure Warp’s agents follow your + coding standards, project conventions, and personal preferences. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { FileTree } from '@astrojs/starlight/components'; + +Warp’s **Rules** feature lets you create reusable guidelines that inform how agents respond to your prompts. Rules help tailor responses to match your coding standards, project conventions, and personal preferences, making agent interactions smarter and more consistent. + +Warp supports two types of rules: **Global Rules** and **Project Rules**. + +<VideoEmbed url="https://youtu.be/fDr0-3bLxMQ" /> + +## Global Rules + +Global Rules apply across all projects and contexts. They're ideal for: + +* Coding standards and best practices +* Workspace-wide guidelines +* Tool configurations or preferences you want applied everywhere + +Warp may also suggest Global Rules based on your usage patterns to make future interactions smarter and more consistent. +## Project Rules + +Project Rules live in your codebase and apply automatically when working within that project. They're stored in an `AGENTS.md` file (or `WARP.md` for backwards compatibility) and can be: + +* Placed in the root of your repository +* Added in subdirectories for more targeted guidance + +:::note +Warp uses `AGENTS.md` as the default project rules file. Existing `WARP.md` files are still fully supported—if you have `WARP.md`, it will continue to work as expected. You can also rename `WARP.md` to `AGENTS.md` at any time without additional changes. + +If both `WARP.md` and `AGENTS.md` exist in the same directory, `WARP.md` takes priority. +::: + +:::caution +The filename must be in **all caps** for Warp to recognize it (e.g., `AGENTS.md`, not `agents.md` or `Agents.md`). We recommend creating `AGENTS.md` for new projects. +::: + +**When you're in a directory:** + +* Warp automatically applies the `AGENTS.md` (or `WARP.md`) in the root and in the current directory. +* If you edit files in another subdirectory, Warp makes a best-effort attempt to include that subdirectory's rules file as well. + +Example project structure: + +<FileTree> +- project/ + - api/ + - AGENTS.md API-specific rules + - ui/ + - AGENTS.md UI-specific rules + - AGENTS.md Project-wide rules +</FileTree> + +How Warp applies these Project Rules: + +* **If the current directory is `ui/`** + * Automatically applied: `project/AGENTS.md` and `project/ui/AGENTS.md` + * Best effort: `project/api/AGENTS.md` if editing files there +* **If the current directory is `api/`** + * Automatically applied: `project/AGENTS.md` and `project/api/AGENTS.md` + * Best effort: `project/ui/AGENTS.md` if editing files there + +### **Rules precedence** + +When multiple rules apply, Warp follows this order of precedence: + +1. Rules in the current subdirectory's project rules file +2. Rules in the root directory's project rules file +3. Global Rules + +This ensures the most specific, project-relevant rules take priority over broader ones. + +--- + +## How to access Rules + +* From [Warp Drive](/knowledge-and-collaboration/warp-drive/): **Personal** > **Rules** +* From the [Command Palette](/terminal/command-palette/): search for "Open AI Rules" +* From the Settings panel: **Settings** > **Agents** > **Knowledge** > **Manage Rules** + * Here, you can manage both Global as well as Project Rules. +* From the macOS Menu: `AI > Open Rules` +* From the Slash Commands menu: `/open-project-rules` to open Project Rules directly in Warp's code editor + +![Project Rules UI open in a Rules pane](../../../../assets/agent-platform/project-scoped-rules-pane.png) + +## How to create, edit, or delete Rules + +#### Global Rules + +* **From Warp Drive Rules pane:** **Personal** > **Rules** > **Global**\ + Add, edit, or delete any number of rules. Each rule can include: + * Name (optional) + * Description (what the rule does and when to apply it) +* **From the Slash Commands menu:** `/add-rule` in Auto or Agent input modes to create a new Global Rule (automatically opens the Warp Drive Rules pane). + +<VideoEmbed url="https://www.loom.com/share/3a49462c01e149cf9c040130cebe1184?hideEmbedTopBar=true&hide_owner=true&hide_share=true&hide_title=true" title="Rules Demo (legacy) with just Global Rules. Project rules can also be found there." /> + +#### Project Rules + +* **When in a directory, set up Project Rules with a slash command:** Use `/init` in Auto-Detection or Agent Mode to: + * Begin indexing your codebase or display indexing status + * Generate an `AGENTS.md` file with initial context, or + * Link an existing Rules file to `AGENTS.md` + * Warp currently supports linking the following external Rules files: `CLAUDE.md`, `.cursorrules`, `AGENT.md`, `GEMINI.md`, `.clinerules`, `.windsurfrules`, `.github/copilot-instructions.md` + +To view all Project Rules and open them in Warp, access it via the Warp Drive Rules pane: **Personal** > **Rules** > **Project-based** + +### Rules as Agent context + +When relevant, Agents automatically pull in applicable rules to guide their responses. Rules used in an interaction will appear in the conversation under **References** or marked as derived from a specific rule. + +![Context derived from memory](../../../../assets/agent-platform/context-derived-from-memory.png) + +![Context derived from memory](../../../../assets/agent-platform/context-references-memory.png) + +### Rules privacy + +See our [Privacy Page](/support-and-community/privacy-and-security/privacy/) for more information on how we handle data with Rules. diff --git a/src/content/docs/agent-platform/capabilities/skills.mdx b/src/content/docs/agent-platform/capabilities/skills.mdx new file mode 100644 index 0000000..49d9370 --- /dev/null +++ b/src/content/docs/agent-platform/capabilities/skills.mdx @@ -0,0 +1,443 @@ +--- +title: Skills +description: >- + Create reusable instruction sets that teach agents specific tasks and share + expertise across your team. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { FileTree } from '@astrojs/starlight/components'; + +Skills allow you to create reusable, shareable instructions that agents can invoke when performing tasks. Instead of repeating detailed prompts, you can encapsulate common workflows, coding patterns, or domain expertise into skill files that agents automatically discover and use. + +## Key features + +* **Reusable instructions** - Define a task once and let Agents use it whenever relevant +* **Project and global scopes** - Create skills specific to a project or available across all projects +* **Automatic discovery** - Agents are aware of all available skills and invoke them when appropriate +* **Simple markdown format** - Skills are just markdown files with a small amount of metadata +* **Supporting files** - Include scripts, templates, or other resources alongside your skill instructions +* **Slash command invocation** - Invoke any skill directly with `/{skill-name}` +* **Parameterized skills** - Use argument placeholders to create dynamic, reusable skill templates + +## How Skills work + +When you start an [Agent conversation](/agent-platform/local-agents/interacting-with-agents/), the Agent receives a list of all available skills with their names and descriptions. + +When the Agent determines that a skill would help accomplish your task, it loads the skill's full instructions and follows them to complete the task. + +:::caution +Skill discovery is based on your current working directory. For Git repositories, Warp includes all skills from your current directory up through the repository root. If you're working in project A, you won't have access to skills from project B. +::: + +:::note +Skills complement Rules, which provide persistent guidelines that Agents always follow. Use Rules for constraints and preferences; use Skills for specific task workflows. +::: + +### Skill name conflicts + +If you have skills with the same name in multiple directories, Warp handles the conflict differently depending on how the skill is invoked: + +* **Natural language** - The Agent receives a list of all in-scope skills including their names, descriptions, and file paths. The Agent can see all available options and chooses the appropriate skill based on its path. +* **Slash commands** - When multiple skills share the same name, Warp displays all matching skills in the menu. You select which one to use based on the description. +* **Background resolution** - When Warp resolves skill names automatically (without direct user selection), it prioritizes home directory (global) skills first, then skills from higher directories (closer to the repository root). + +### Example interactions + +You can invoke skills in two ways: + +**Using natural language** - Describe what you want to accomplish: + +* "Use the deploy skill to push to staging" +* "Check the docs for broken links" (invokes a link-checking skill) +* "Create a DOCX file with my project's README content" +* "Draft documentation for the new API endpoint based on this PR" + +**Using slash commands** - Invoke a skill directly with `/{skill-name}`: + +* `/deploy` - Invokes the deploy skill +* `/add-feature-flag` - Invokes the add-feature-flag skill + +The Agent recognizes when your request matches a skill's purpose, loads the skill instructions, and follows them to complete the task. + +## Skill file format + +Skills are markdown files with YAML frontmatter. Each skill must have: + +* **name** - A unique identifier for the skill (typically kebab-case) +* **description** - A brief explanation of what the skill does and when to use it + +### Basic structure + +```markdown +--- +name: your-skill-name +description: Brief description of what this skill does and when to use it +--- + +# Your Skill Name + +## Instructions +Provide clear, step-by-step guidance for the agent. +You can use argument placeholders like $ARGUMENTS or $0 in the body (see [Skill arguments](#skill-arguments)). + +## Examples +Show concrete examples of using this skill. +``` + +### Example skill file + +Here's a complete example of a skill that helps create feature flags: + +```markdown +--- +name: add-feature-flag +description: Add a new feature flag to the codebase with proper configuration and documentation +--- + +# Add Feature Flag + +## Instructions +1. Ask the user for the feature flag name and default value +2. Add the flag definition to `config/feature_flags.yaml` +3. Create a helper function in `src/utils/flags.ts` +4. Update the feature flags documentation in `docs/FEATURE_FLAGS.md` + +## Configuration Format +Feature flags should follow this format in the YAML file: + +feature_name: + default: false + description: "What this flag controls" + owner: "team-name" + +## Examples +- "Add a feature flag for the new checkout flow" +- "Create a flag to enable dark mode for beta users" +``` + +## Skill arguments + +Skills can include argument placeholders that are automatically substituted with values you provide when invoking the skill. This lets you create reusable, parameterized skill templates. + +<VideoEmbed url="https://www.loom.com/share/4cb0a80e567c41788816cd9b5acbc7ed" title="Using Skill Arguments in Warp" /> + +### Argument syntax + +Three placeholder formats are supported: + +* **`$ARGUMENTS`** — Replaced with the full raw argument string (everything after the skill name). +* **`$ARGUMENTS[N]`** — Replaced with the Nth whitespace-separated argument (0-indexed). For example, `$ARGUMENTS[0]` is the first argument, `$ARGUMENTS[1]` is the second, etc. +* **`$N`** — Shorthand for `$ARGUMENTS[N]`. For example, `$0` is equivalent to `$ARGUMENTS[0]`. + +### How argument substitution works + +When you invoke a skill, any text you type after the skill name is treated as the argument string. The argument string is split on whitespace to produce individual indexed arguments. + +**If the skill contains argument placeholders** (`$ARGUMENTS`, `$ARGUMENTS[N]`, or `$N`), the placeholders are replaced with the corresponding argument values before the skill instructions are sent to the agent. + +**If the skill does not contain any argument placeholders**, the extra text you provide is passed to the agent as a separate user message alongside the skill instructions. This means you can always add context when invoking a skill, whether or not it uses argument placeholders. + +:::note +If a placeholder references an argument index that wasn't provided (e.g. `$2` when only two arguments were given), the placeholder is left as-is in the skill content. +::: + +### Example: Skill with arguments + +Here's a skill that uses arguments to explain a topic for a specific audience: + +```markdown +--- +name: explain-topic +description: Explain a topic for a specific audience in a given tone +--- + +# Explain Topic + +Explain $0 for an audience of $1 professionals. + +Use a $2 tone. + +Full request: $ARGUMENTS +``` + +Invoking this skill with: + +``` +/explain-topic bears engineering fun +``` + +Produces the following instructions for the agent: + +``` +Explain bears for an audience of engineering professionals. + +Use a fun tone. + +Full request: bears engineering fun +``` + +### Example: Skill without arguments + +If a skill has no argument placeholders: + +```markdown +--- +name: greet +description: Greet the user with an Australian-style hello +--- + +# Greet + +Greet the user warmly in an Australian style. +``` + +Invoking with extra text: + +``` +/greet say it in French +``` + +The skill instructions are sent first, then "say it in French" is passed as a follow-up user message. The agent sees both and can combine them — in this case, greeting in French with an Australian flair. + +## Skill locations + +Skills can be stored at two levels: project-level (accessible only within that project) and user-level (accessible from any project). + +### Project skills + +Project skills live in your repository and are available when you're working in that project. We recommend storing them at your project root, but skills in subdirectories are also discovered when you're working within that subdirectory. This is useful for monorepos with separate `./frontend` and `./backend` directories. + +Store them in any of these directories: + +* **`.agents/skills/`** (recommended) +* **`.warp/skills/`** +* **`.claude/skills/`** +* **`.codex/skills/`** +* **`.cursor/skills/`** +* **`.gemini/skills/`** +* **`.copilot/skills/`** +* **`.factory/skills/`** +* **`.github/skills/`** +* **`.opencode/skills/`** + +Each skill must be in its own subdirectory with a `SKILL.md` file. Any supporting files (scripts, templates, configs) should be referenced in `SKILL.md` so the Agent knows they exist: + +<FileTree> +- your-project/ + - .agents/ + - skills/ + - add-feature-flag/ + - SKILL.md + - run-migrations/ + - SKILL.md + - .claude/ + - skills/ + - review-code/ + - SKILL.md + - .github/ + - skills/ + - create-release/ + - SKILL.md +</FileTree> + +:::note +Warp scans all supported skill directory names in your project root, allowing you to maintain skills compatible with multiple AI coding tools in the same repository. +::: + +### Root directory skills (global) + +Root directory skills are stored in your home directory and are available across all projects on your machine. These are useful for personal workflows, coding patterns, or procedures you use regardless of the specific project. + +Store global skills in any of these directories in your home folder: + +* **`~/.agents/skills/`** (recommended) +* **`~/.warp/skills/`** +* **`~/.claude/skills/`** +* **`~/.codex/skills/`** +* **`~/.cursor/skills/`** +* **`~/.gemini/skills/`** +* **`~/.copilot/skills/`** +* **`~/.factory/skills/`** +* **`~/.github/skills/`** +* **`~/.opencode/skills/`** + +The directory structure is the same as project skills: + +<FileTree> +- `~/.agents/` + - skills/ + - git-workflow/ + - SKILL.md + - code-review/ + - SKILL.md +</FileTree> + +### Project vs Root directory skills + +Understanding when to use each level: + +**Project skills** are best for: + +* Project-specific workflows (deployment, testing, migrations) +* Team-shared procedures and standards +* Repository-specific automation and tooling +* Domain-specific patterns for that codebase + +**Root directory skills** are best for: + +* Personal coding preferences and patterns +* General-purpose workflows used across all projects +* Cross-project automation (git workflows, documentation templates) +* Professional standards you apply everywhere + +## Creating skills + +### Step 1: Choose a location + +Decide whether your skill should be: + +* **Project-specific** - Place it in one of your project's skill directories (`.agents/skills/`, `.warp/skills/`, `.claude/skills/`, etc.) +* **Global** - Place it in one of your home directory's skill folders (`~/.agents/skills/`, `~/.warp/skills/`, `~/.claude/skills/`, etc.) + +### Step 2: Create the directory structure + +Create a subdirectory for your skill with a descriptive name: + +```bash +mkdir -p .agents/skills/my-new-skill +``` + +### Step 3: Write the skill file + +Create `SKILL.md` in your skill directory: + +```bash +touch .agents/skills/my-new-skill/SKILL.md +``` + +### Step 4: Add content + +Write your skill with clear instructions: + +```markdown +--- +name: my-new-skill +description: One-line description of what this skill does +--- + +# My New Skill + +## When to use +Explain the scenarios where this skill is helpful. + +## Instructions +1. First step the Agent should take +2. Second step with specific details +3. Continue with clear, actionable steps + +## Important notes +- Any constraints or requirements +- Common pitfalls to avoid +``` + +## Skills with supporting files + +Skills can include supporting files like scripts, templates, or configuration files. Place these files in the same directory as your `SKILL.md`: + +<FileTree> +- .agents/skills/ + - check-broken-links/ + - SKILL.md + - `check_links.py` Supporting script + - config.yaml Configuration file +</FileTree> + +In your skill instructions, reference these files using relative paths. For example, in your `SKILL.md`: + +``` +## Running the check + +From the project root: + +python3 .agents/skills/check-broken-links/check_links.py --internal-only +``` + +This pattern is useful for: + +* **Automation scripts** - Python, shell, or Node scripts that perform complex tasks +* **Templates** - Boilerplate files the Agent can copy and customize +* **Configuration** - Default settings or schemas the skill references + +## Managing skills + +### Viewing available skills + +Ask the Agent what skills are available: + +``` +What skills do I have? +``` + +The Agent lists all discovered skills with their names and descriptions. This includes skills from all supported directories in both your current project and your home directory. + +### Editing skills + +Use the [`/open-skill`](/agent-platform/capabilities/slash-commands/) slash command to modify existing skills: + +``` +/open-skill +``` + +This opens an interactive menu where you can: + +* Browse project and root directory skills +* See which directory each skill is located in +* Open the skill file in your editor + +### Best practices + +* **Write clear descriptions** - The description is how Agents decide whether to use your skill +* **Be specific in instructions** - Include exact file paths, command syntax, and expected formats +* **Include examples** - Show concrete use cases to help Agents understand intent +* **Keep skills focused** - Each skill should do one thing well +* **Use consistent naming** - Follow a naming convention like `verb-noun` (e.g., `add-feature-flag`, `run-migrations`) +* **Version control your skills** - Commit project skills to your repo so the whole team benefits + +## Pre-built skills + +Warp maintains a public collection of ready-to-use skills in the [warpdotdev/oz-skills](https://github.com/warpdotdev/oz-skills) repository. You can browse these skills for inspiration, copy them directly into your project's `.agents/skills/` directory, or adapt them to fit your team's workflows. + +These same skills also appear as suggested agents in the [Oz web app](/agent-platform/cloud-agents/oz-web-app/), where you can run them directly in the cloud. + +## Invoking skills with a prompt + +You can pass additional context or instructions to a skill when invoking it with a slash command. + +**Using slash commands with a prompt:** + +* `/deploy push the latest changes to staging` — Invokes the deploy skill with additional instructions to target staging +* `/code-review focus on error handling and edge cases` — Invokes the code-review skill with guidance on what to prioritize + +This is useful when you want to reuse a skill's workflow but tailor the execution to a specific situation without modifying the skill itself. + +## Running agents from skills + +Skills can be used with both local and [cloud agents](/agent-platform/cloud-agents/overview/) to create reusable, automated workflows. When running an agent via the CLI, web app, or API, you can specify a skill to provide the base instructions for the agent. + +For a complete guide to running skill-based agents—including CLI usage, the Oz web app, scheduling, skill discovery, and API integration—see [Skills as Agents](/agent-platform/cloud-agents/skills-as-agents/). + +## Related features + +* [**Rules**](/agent-platform/capabilities/rules/) - Set persistent guidelines and constraints for Agent behavior +* [**MCP Servers**](/agent-platform/capabilities/mcp/) - Expose external data sources and tools to Agents +* [**Cloud Agents**](/agent-platform/cloud-agents/overview/) - Run Agents in the cloud on schedules or triggers +* [**Agent Profiles**](/agent-platform/capabilities/agent-profiles-permissions/) - Control Agent permissions and autonomy + +--- + +## Next steps + +Skills become even more powerful when you automate and share them. + +* **[Scheduled Agents quickstart](/agent-platform/cloud-agents/triggers/scheduled-agents-quickstart/)** - Run a skill on a recurring cron schedule for tasks like weekly dependency checks or daily code cleanup. +* **[Integrations quickstart](/agent-platform/cloud-agents/integrations/quickstart/)** - Trigger skills from Slack or Linear so your team can invoke agent workflows from the tools they already use. diff --git a/src/content/docs/agent-platform/capabilities/slash-commands.mdx b/src/content/docs/agent-platform/capabilities/slash-commands.mdx new file mode 100644 index 0000000..ef24b7b --- /dev/null +++ b/src/content/docs/agent-platform/capabilities/slash-commands.mdx @@ -0,0 +1,44 @@ +--- +title: Slash Commands +description: >- + Use Slash Commands in Agent Mode or Auto-Detection Mode to quickly run + built-in actions or saved prompts without leaving the input field. +--- + +When using Agent Mode or Auto-Detection Mode, typing `/` in the input field opens the Slash Commands menu. + +![Slash Commands menu](../../../../assets/agent-platform/slash-commands-menu.png) + +As you type, the menu filters results in real time, making it easy to find and run the command or prompt you need. + +## Static slash commands + +Warp currently supports the following built-in Slash Commands: + +<table><thead><tr><th width="211.64453125">Slash Command</th><th>Description</th></tr></thead><tbody><tr><td><code>/add-mcp</code></td><td>Add a new <a href="/agent-platform/capabilities/mcp/">MCP server</a>.</td></tr><tr><td><code>/add-prompt</code></td><td>Add a new <a href="/knowledge-and-collaboration/warp-drive/prompts/">Agent Prompt</a> in Warp Drive.</td></tr><tr><td><code>/add-rule</code></td><td>Add a new <a href="/agent-platform/capabilities/rules/">Global Rule</a> for the Agent.</td></tr><tr><td><code>/agent</code></td><td>Start a new <a href="/agent-platform/local-agents/interacting-with-agents/">agent conversation</a>. Optionally include a prompt to send immediately.</td></tr><tr><td><code>/changelog</code></td><td>Open the latest Warp <a href="/changelog/">changelog</a>.</td></tr><tr><td><code>/cloud-agent</code></td><td>Start a new <a href="/agent-platform/cloud-agents/overview/">cloud agent conversation</a>. <code>{'*'}</code></td></tr><tr><td><code>/compact</code></td><td>Free up context by summarizing conversation history.</td></tr><tr><td><code>/compact-and</code></td><td>Compact the current conversation and then send a follow-up prompt.</td></tr><tr><td><code>/conversations</code></td><td>Open <a href="/agent-platform/local-agents/interacting-with-agents/">conversation history</a>.</td></tr><tr><td><code>/cost</code></td><td>Toggle credit usage details in the current conversation.</td></tr><tr><td><code>/create-environment</code></td><td>Create a <a href="/agent-platform/cloud-agents/environments/">Warp Environment</a> (Docker image + repos) via guided setup. <code>{'*'}</code></td></tr><tr><td><code>/create-new-project</code></td><td>Have the Agent walk you through creating a new coding project. <code>{'*'}</code></td></tr><tr><td><code>/export-to-clipboard</code></td><td>Export the current conversation to clipboard in markdown format.</td></tr><tr><td><code>/export-to-file</code></td><td>Export the current conversation to a markdown file.</td></tr><tr><td><code>/feedback</code></td><td>Send feedback to the Warp team. Only the Agent-drafted flow consumes credits. See <a href="/support-and-community/troubleshooting-and-support/sending-us-feedback/#using-feedback-in-warp">Using <code>/feedback</code> in Warp</a> for details. <code>{'*'}</code></td></tr><tr><td><code>/fork</code></td><td><a href="/agent-platform/local-agents/interacting-with-agents/conversation-forking/">Forks the current conversation</a> into a new thread with the full context and history of the original. <br /><br />You can optionally include a prompt that will be sent immediately in the forked conversation.</td></tr><tr><td><code>/fork-and-compact</code></td><td><a href="/agent-platform/local-agents/interacting-with-agents/conversation-forking/">Forks the current conversation</a> and automatically compacts the forked version.<br /><br />Useful when you want a fresh, summarized starting point that preserves relevant context while trimming the rest.</td></tr><tr><td><code>/fork-from</code></td><td>Open a searchable menu to <a href="/agent-platform/local-agents/interacting-with-agents/conversation-forking/">fork the conversation</a> from a specific query. Select a query to create a fork that includes everything up to that point.</td></tr><tr><td><code>/index</code></td><td>Index the current codebase using <a href="/agent-platform/capabilities/codebase-context/">Codebase Context</a>.</td></tr><tr><td><code>/init</code></td><td>Index the current codebase and generate an <a href="/agent-platform/capabilities/rules/">AGENTS.md file</a>. <code>{'*'}</code></td></tr><tr><td><code>/model</code></td><td>Switch the base agent model for the current conversation.</td></tr><tr><td><code>/new</code></td><td>Start a new <a href="/agent-platform/local-agents/interacting-with-agents/">agent conversation</a> (alias for <code>/agent</code>).</td></tr><tr><td><code>/open-code-review</code></td><td>Open the <a href="/code/code-review/">code review</a> pane.</td></tr><tr><td><code>/open-file</code></td><td>Open a file for editing in Warp's <a href="/code/code-editor/">code editor</a>.</td></tr><tr><td><code>/open-mcp-servers</code></td><td>View the status of your <a href="/agent-platform/capabilities/mcp/">MCP servers</a>.</td></tr><tr><td><code>/open-project-rules</code></td><td>Open the <a href="/agent-platform/capabilities/rules/#project-rules">Project Rules</a> file (<code>AGENTS</code>).</td></tr><tr><td><code>/open-repo</code></td><td>Switch to another indexed repository.</td></tr><tr><td><code>/open-rules</code></td><td>View all of your global and project <a href="/agent-platform/capabilities/rules/">rules</a>.</td></tr><tr><td><code>/open-settings-file</code></td><td>Open the Warp <a href="/terminal/settings/">settings file</a> (<code>settings.toml</code>) in Warp's code editor.</td></tr><tr><td><code>/open-skill</code></td><td>Open an interactive menu to browse and edit project or global <a href="/agent-platform/capabilities/skills/">skills</a>.</td></tr><tr><td><code>/orchestrate</code></td><td>Break a task into subtasks and run them in parallel with multiple agents. <code>{'*'}</code></td></tr><tr><td><code>/plan</code></td><td>Prompt the Agent to do some research and create a <a href="/agent-platform/capabilities/planning/">plan</a> for a task.</td></tr><tr><td><code>/pr-comments</code></td><td>Pull GitHub PR review comments into Warp. <code>{'*'}</code></td></tr><tr><td><code>/profile</code></td><td>Switch the active <a href="/agent-platform/capabilities/agent-profiles-permissions/">execution profile</a>.</td></tr><tr><td><code>/prompts</code></td><td>Search saved <a href="/knowledge-and-collaboration/warp-drive/prompts/">prompts</a>.</td></tr><tr><td><code>/rename-tab</code></td><td>Rename the current tab. Include the new tab name as an argument (for example, <code>/rename-tab deploy</code>).</td></tr><tr><td><code>/rewind</code></td><td>Rewind to a previous point in the conversation.</td></tr><tr><td><code>/skills</code></td><td>Invoke a <a href="/agent-platform/capabilities/skills/">skill</a> from a searchable menu.</td></tr><tr><td><code>/usage</code></td><td>Open <a href="/support-and-community/plans-and-billing/">billing and usage</a> settings.</td></tr></tbody></table> + +:::caution +Slash commands marked with a `*` consume credits to complete the task. +::: + +#### Using Agent Prompts via Slash Commands + +In addition to static commands, the menu also shows [Agent Prompts](/knowledge-and-collaboration/warp-drive/prompts/) saved in your [Warp Drive](/knowledge-and-collaboration/warp-drive/). + +* These prompts can be custom ones you’ve created or ones shared with you. +* As you type after `/`, prompts are filtered dynamically, so you can quickly run them without leaving the input field. + +![Slash Commands menu with filtered Agent Prompts](../../../../assets/agent-platform/slash-commands-prompts.png) + +### Tips + +* **Context-aware:** Many Slash Commands use your current working directory or file selection as context. +* **Quick access:** Use `/` from anywhere in Agent Mode or Auto-Detection Mode to avoid navigating through menus. + +### Example of using a Slash Command + +Below is an example interaction when `/init` is run: + +![/init setup flow; 1 of 2](../../../../assets/agent-platform/init-setup-flow-1.png) + +![/init setup flow; 2 of 2](../../../../assets/agent-platform/init-setup-flow-2.png) diff --git a/src/content/docs/agent-platform/capabilities/task-lists.mdx b/src/content/docs/agent-platform/capabilities/task-lists.mdx new file mode 100644 index 0000000..2ce6b8a --- /dev/null +++ b/src/content/docs/agent-platform/capabilities/task-lists.mdx @@ -0,0 +1,40 @@ +--- +title: Agent Task Lists +description: >- + Track and manage complex Agent workflows with automatic task lists that + break requests into clear, actionable steps and update progress in real + time. +--- + +The Agent can automatically break down complex requests into clear, trackable steps in the form of a task list with to-do items.\ +\ +When you make a sufficiently complex request that requires multiple actions, the Agent will automatically create a list of steps, execute them in order, and track progress from start to finish. There’s no need to adjust settings or enable a special mode—the Agent detects and creates task lists automatically. + +![An example of a task list in progress.](../../../../assets/agent-platform/in-progress-tasklist.png) + +### How task lists work + +1. **Automatic task creation** — For complex requests, the Agent generates a structured list of tasks to complete. +2. **Step-by-step execution** — The Agent works through each task in sequence, updating statuses in real time. +3. **Summary** — Once all tasks are complete, the Agent provides a concise summary of what was done, including outputs, results, and relevant context. If any tasks were skipped or couldn’t be completed, it explains why. + +After each step is completed, there is also a completion marker in the Agent conversation. + +![Completion markers inside the Agent conversation after each task is completed.](../../../../assets/agent-platform/completion-markers.png) + +### Task statuses + +Each task in the list has a visual indicator so you can quickly see its progress. + +<table><thead><tr><th width="145.5">Status</th><th width="186.2265625">Icon</th><th>Meaning</th></tr></thead><tbody><tr><td>Current task</td><td>● (filled circle)</td><td>The Agent is actively working on this task.</td></tr><tr><td>Completed</td><td>✔︎</td><td>The Agent has finished this task successfully.</td></tr><tr><td>Not started</td><td>○ (empty circle)</td><td>The task is in the queue but work hasn’t begun.</td></tr><tr><td>Cancelled</td><td>■ (filled square)</td><td>The task was stopped before completion.</td></tr></tbody></table> + +![Task list popup showing 4 of 6 tasks completed with status indicators for each step](../../../../assets/agent-platform/tasklist-small.png) + +### Task list access + +During any Agent conversation, a task list chip appears at the bottom-right of the screen (when input is pinned to the bottom; otherwise, it may appear along the right side). + +* Click the chip to open the current task list. +* You can collapse or expand the view at any time without interrupting the Agent. + +![Access the task list during an Agent conversation in the task list chip in the conversation.](../../../../assets/agent-platform/tasklist-popup.png) diff --git a/src/content/docs/agent-platform/capabilities/web-search.mdx b/src/content/docs/agent-platform/capabilities/web-search.mdx new file mode 100644 index 0000000..65ad0d3 --- /dev/null +++ b/src/content/docs/agent-platform/capabilities/web-search.mdx @@ -0,0 +1,95 @@ +--- +title: Web Search +description: >- + Warp’s web search lets agents pull in real-time information, documentation, + and cited sources whenever it improves an answer. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Warp includes native web search for models that support first-party search tools. When enabled, agents can look up information in real time, consult documentation, retrieve current version numbers, and cite the sources used to generate responses. + +<VideoEmbed url="https://www.loom.com/share/06a4ba98f2e0446d80cb37aa4c23848c" /> + +This page covers how web search works, supported models, what you can expect inside Warp, configuration options, and how this differs from attaching URLs directly to a prompt. + +--- + +### When the Agent uses web search + +Models initiate a web search when it improves the quality or accuracy of an answer. **Common scenarios include:** + +* Retrieving official documentation or API references +* Getting the latest version of a library or tool +* Checking error messages, GitHub issues, or StackOverflow discussions +* Looking up ongoing incidents or recent changes +* Answering questions where recency matters (e.g., “best approach in 2025 to…”) + +Web searches are automatically triggered when the model considers them useful. You don’t need special syntax. + +### How web search works in Warp + +**When a search occurs:** + +1. Warp shows a “Searching the web…” indicator inside the conversation. +2. You can expand the search result to view: + * The query issued + * The pages retrieved +3. **The model reads results and produces a grounded response.** + * Claude models cite sources in the references footer. + * OpenAI models use inline citations and also show references in the footer. + +### Supported and unsupported models + +Web search is available only for models that offer a native web search integration, that works in tandem with other custom tools. + +**Models that support web search** + +* Anthropic: `Claude 4.6 Series`, `Claude 4.5 Series`, `Claude 4 Series` +* OpenAI: + * `GPT-5.4`, `GPT-5.3 Codex`, `GPT-5.2 Codex`, `GPT-5.2` + +Warp uses each vendor’s official tool: + +* **Claude Web Search**: [https://docs.claude.com/en/docs/agents-and-tools/tool-use/web-search-tool](https://docs.claude.com/en/docs/agents-and-tools/tool-use/web-search-tool) +* **OpenAI Web Search**: [https://developers.openai.com/api/docs/guides/tools-web-search](https://developers.openai.com/api/docs/guides/tools-web-search) + +:::note +**Note**: We plan to add native web search for additional models as soon as their APIs fully support it. We’ll continue updating the list of search-capable models as vendors roll out broader tooling. We're also exploring custom web search tools that'll work across all models. +::: + +### Viewing search results + +You can inspect the web search UI at any time: + +* Expand the **Web Search** section in the agent response +* You can see: + * The list of pages fetched + * The text used to answer your question + * Citations and reference metadata + +![An agent conversation in Warp showing the expanded Web Search section with the query 'Stripe API latest version 2025' and a list of 10 retrieved URLs](../../../../assets/agent-platform/web-search-results.png) + +This makes it easy to verify accuracy, audit reasoning, and validate sources. + +### Enabling or disabling web search + +Web search is controlled per [Profiles & Permissions](/agent-platform/capabilities/agent-profiles-permissions/). + +To configure: + +1. In the Warp app, navigate to **Settings** > **Agents** > **Profiles**. +2. Next to the agent profile, click **Edit**. +3. Scroll to **Call web tools** and toggle the setting on or off. + +![The Profiles page in Warp Settings, with the Profile Editor open and the Call web tools toggle enabled](../../../../assets/agent-platform/web-search-settings.png) + +Disabling this prevents the agent from performing searches, even if a model would normally use them. + +### Credit usage + +Web search incurs two types of credit usage: + +1. A small fixed cost per search invocation +2. Additional cost proportional to retrieved content, since retrieved text is passed to the model + +You’ll see these contributions itemized in the conversation’s credit usage footer, alongside model calls, planning calls, and other tool usage. diff --git a/src/content/docs/agent-platform/cli-agents/claude-code.mdx b/src/content/docs/agent-platform/cli-agents/claude-code.mdx new file mode 100644 index 0000000..6f3578f --- /dev/null +++ b/src/content/docs/agent-platform/cli-agents/claude-code.mdx @@ -0,0 +1,72 @@ +--- +title: Claude Code +description: >- + Set up Claude Code in Warp with full notification support, rich input, code + review, and more. +--- + +Claude Code is Anthropic's agentic coding tool that operates directly in your terminal. It understands your codebase, executes commands, edits files, and manages Git workflows — all through natural language. For full documentation, see the [official Claude Code docs](https://code.claude.com/docs). + +Warp auto-detects Claude Code when you run it, giving you access to rich input controls, code review, agent notifications, and other integrated features. For a product overview, see [Claude Code in Warp](https://warp.dev/agents/claude-code). + +For installation, authentication, project configuration, and productivity tips, see the [How to set up Claude Code](/guides/external-tools/how-to-set-up-claude-code/) guide. + +## Setting up notifications + +Warp supports agent notifications for Claude Code through a plugin. Once installed, Warp surfaces in-app and desktop alerts when Claude Code needs your input — such as command approval, code review, or error intervention. + +### Auto-install + +Each time you run Claude Code in Warp without the notification plugin installed, a notification chip appears offering one-click installation. Click the chip to install the plugin automatically. After installation, Warp immediately starts receiving notifications from Claude Code. + +### Manual install + +:::note +The notification plugin requires `jq`. Install it with your package manager (e.g., `brew install jq` on macOS) if it's not already available. +::: + +If the auto-install chip doesn't appear or fails to install the plugin, install it manually. From inside Claude Code, run: + +```bash +/plugin marketplace add warpdotdev/claude-code-warp +/plugin install warp@claude-code-warp +``` + +Or from your terminal (outside of Claude Code): + +```bash +claude plugin marketplace add warpdotdev/claude-code-warp +claude plugin install warp@claude-code-warp +``` + +After installing, restart Claude Code or run `/reload-plugins` to activate the plugin. + +:::note +If installation fails or you have an outdated version of the plugin, remove it first with `claude plugin marketplace remove claude-code-warp`, then re-run the install commands above. +::: + +### Installation instructions banner + +If the auto-install chip doesn't work, or if you're running Claude Code over SSH or on a remote machine, Warp displays an installation instructions banner directly in the terminal. The banner shows step-by-step commands that you can run in place — no need to switch between tabs or copy-paste from external documentation. + +For plugin source and updates, see the [claude-code-warp GitHub repository](https://github.com/warpdotdev/claude-code-warp). + +## Supported Warp features + +Claude Code supports the full set of Warp's agent integration features: + +* **Agent notifications** - Receive in-app and desktop alerts when Claude Code needs your attention. The notification UI displays your current git branch alongside agent status. +* **Rich input editor** - Press `Ctrl-G` to open an expanded input editor for composing longer prompts. +* **Code review** - Send inline review comments directly to the agent from Warp's code review panel. +* **Attach code as context** - Select code and send it to the agent as context. +* **Vertical tabs with agent metadata** - Monitor Claude Code sessions with status indicators in Warp's tab bar. +* **Tab Configs** - Save and restore Claude Code session configurations. +* **Remote Control** - Share your Claude Code session with teammates via session sharing. + +## Related pages + +* [How to set up Claude Code](/guides/external-tools/how-to-set-up-claude-code/) — step-by-step setup guide +* [Claude Code in Warp](https://warp.dev/agents/claude-code) — product overview +* [Third-Party CLI Agents Overview](/agent-platform/cli-agents/overview/) +* [OpenCode](/agent-platform/cli-agents/opencode/) +* [Codex](/agent-platform/cli-agents/codex/) diff --git a/src/content/docs/agent-platform/cli-agents/codex.mdx b/src/content/docs/agent-platform/cli-agents/codex.mdx new file mode 100644 index 0000000..e83173e --- /dev/null +++ b/src/content/docs/agent-platform/cli-agents/codex.mdx @@ -0,0 +1,47 @@ +--- +title: Codex +description: >- + Set up Codex in Warp with notification support, rich input, code review, and + more. +--- + +Codex is OpenAI's open-source coding agent that runs in your terminal. It can write and edit code, execute commands, and navigate your codebase through natural language. For full documentation, see the [Codex GitHub repository](https://github.com/openai/codex). + +Warp auto-detects Codex when you run it, giving you access to rich input controls, code review, and other integrated features. For a product overview, see [Codex in Warp](https://warp.dev/agents/codex). + +For installation, authentication, project configuration, and productivity tips, see the [How to set up Codex CLI](/guides/external-tools/how-to-set-up-codex-cli/) guide. + +## Setting up notifications + +Codex supports native notifications that Warp surfaces as in-app and desktop alerts — such as when Codex completes a task, encounters an error, or needs your input. + +First, update Codex to the latest version — support for this setting was recently added. See the [Codex upgrade instructions](https://developers.openai.com/codex/cli#upgrade). + +Then add the following to `~/.codex/config.toml`: + +```toml +[tui] +notification_condition = "always" +``` + +Then restart Codex. If this config isn't set, Warp displays a setup chip in the terminal with instructions you can follow directly. + +## Supported Warp features + +Codex supports the full set of Warp's agent integration features: + +* **Agent notifications** - Receive in-app and desktop alerts when Codex needs your attention. Requires a one-time config change (see [Setting up notifications](#setting-up-notifications)). +* **Rich input editor** - Press `Ctrl-G` to open an expanded input editor for composing longer prompts. +* **Code review** - Send inline review comments directly to the agent from Warp's code review panel. +* **Attach code as context** - Select code and send it to the agent as context. +* **Vertical tabs with agent metadata** - Monitor Codex sessions with status indicators in Warp's tab bar. +* **Tab Configs** - Save and restore Codex session configurations. +* **Remote Control** - Share your Codex session with teammates via session sharing. + +## Related pages + +* [How to set up Codex CLI](/guides/external-tools/how-to-set-up-codex-cli/) — step-by-step setup guide +* [Codex in Warp](https://warp.dev/agents/codex) — product overview +* [Third-Party CLI Agents Overview](/agent-platform/cli-agents/overview/) +* [Claude Code](/agent-platform/cli-agents/claude-code/) +* [OpenCode](/agent-platform/cli-agents/opencode/) diff --git a/src/content/docs/agent-platform/cli-agents/opencode.mdx b/src/content/docs/agent-platform/cli-agents/opencode.mdx new file mode 100644 index 0000000..f1b598e --- /dev/null +++ b/src/content/docs/agent-platform/cli-agents/opencode.mdx @@ -0,0 +1,48 @@ +--- +title: OpenCode +description: >- + Set up OpenCode in Warp with notification support, rich input, code review, + and more. +--- + +OpenCode is an open-source terminal-based coding agent. It connects to multiple LLM providers and supports tool use, file editing, and command execution from your terminal. For full documentation, see the [OpenCode docs](https://opencode.ai/docs). + +Warp auto-detects OpenCode when you run it, giving you access to rich input controls, code review, agent notifications, and other integrated features. For a product overview, see [OpenCode in Warp](https://warp.dev/agents/opencode). + +For installation, authentication, project configuration, and productivity tips, see the [How to set up OpenCode](/guides/external-tools/how-to-set-up-opencode/) guide. + +## Setting up notifications + +Warp supports agent notifications for OpenCode through a plugin. Once installed, Warp surfaces in-app and desktop alerts when OpenCode needs your input. + +To set up the plugin, add `"@warp-dot-dev/opencode-warp"` to the `plugin` array in your `opencode.json` configuration file: + +```json +{ + "plugin": ["@warp-dot-dev/opencode-warp"] +} +``` + +If the plugin isn't installed, Warp displays an installation chip in the terminal when you run OpenCode, with setup steps you can follow directly. + +For plugin source and updates, see the [opencode-warp GitHub repository](https://github.com/warpdotdev/opencode-warp). + +## Supported Warp features + +OpenCode supports the full set of Warp's agent integration features: + +* **Agent notifications** - Receive in-app and desktop alerts when OpenCode needs your attention. The notification UI displays your current git branch alongside agent status. +* **Rich input editor** - Press `Ctrl-G` to open an expanded input editor for composing longer prompts. +* **Code review** - Send inline review comments directly to the agent from Warp's code review panel. +* **Attach code as context** - Select code and send it to the agent as context. +* **Vertical tabs with agent metadata** - Monitor OpenCode sessions with status indicators in Warp's tab bar. +* **Tab Configs** - Save and restore OpenCode session configurations. +* **Remote Control** - Share your OpenCode session with teammates via session sharing. + +## Related pages + +* [How to set up OpenCode](/guides/external-tools/how-to-set-up-opencode/) — step-by-step setup guide +* [OpenCode in Warp](https://warp.dev/agents/opencode) — product overview +* [Third-Party CLI Agents Overview](/agent-platform/cli-agents/overview/) +* [Claude Code](/agent-platform/cli-agents/claude-code/) +* [Codex](/agent-platform/cli-agents/codex/) diff --git a/src/content/docs/agent-platform/cli-agents/overview.mdx b/src/content/docs/agent-platform/cli-agents/overview.mdx new file mode 100644 index 0000000..6403b66 --- /dev/null +++ b/src/content/docs/agent-platform/cli-agents/overview.mdx @@ -0,0 +1,74 @@ +--- +title: Third-Party CLI Agents +description: >- + Warp provides first-class support for third-party CLI coding agents with a + rich input editor, notifications, code review, and more. +--- + +Warp auto-detects supported CLI agents and enhances them with IDE-level features — a rich input editor, agent notifications, inline code review, remote session control, and more. Run your preferred coding agent inside Warp and get a better experience out of the box. + +This feature set is also known as **universal agent support**. + +## Supported agents + +Warp currently supports the following CLI coding agents: + +* [**Claude Code**](/agent-platform/cli-agents/claude-code/) — Anthropic's CLI coding agent +* [**OpenAI Codex**](/agent-platform/cli-agents/codex/) — OpenAI's CLI coding agent +* [**OpenCode**](/agent-platform/cli-agents/opencode/) — Open-source CLI coding agent +* **Amp** — Sourcegraph's CLI coding agent +* **Auggie** — Augment Code's CLI coding agent +* **Copilot CLI** — GitHub's CLI coding agent +* **Cursor CLI** — Cursor's CLI coding agent +* **Gemini CLI** — Google's CLI coding agent +* **Droid** — Factory's CLI coding agent +* **Pi** — Open-source CLI coding agent + +When you launch a supported agent inside Warp, the **agent toolbelt** appears automatically, giving you quick access to Warp's enhanced features. + +![The agent toolbelt appearing at the bottom of the pane when a supported CLI agent is running in Warp](../../../../assets/agent-platform/cli-agent-toolbelt.png) + +## Feature support + +Not every feature is available for every agent. The table below shows current support. + +| Feature                               | Claude Code | Codex | OpenCode | Amp | Auggie | Copilot CLI | Cursor | Gemini CLI | Droid | Pi | +|---|---|---|---|---|---|---|---|---|---|---| +| Rich input editor (`Ctrl-G`) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Agent notifications | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | +| Code review comments | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Attach code as context | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Vertical tabs + metadata | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Tab Configs | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Remote Control | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | + +:::note +Agent notifications require a one-time setup. Claude Code and OpenCode use a Warp notification plugin. Codex uses a native config change. See the individual agent pages for setup instructions. Amp, Auggie, Copilot CLI, Cursor, Gemini CLI, Droid, and Pi don't support notifications yet. +::: + +## Customizing the toolbelt + +The chips and buttons on the CLI agent toolbelt can be reordered, hidden, or moved between the left and right sides. Your layout is saved and persists across app restarts. + +In the Warp app, open the **Edit CLI agent toolbelt** modal in one of two ways: + +* Right-click the input area while a supported CLI coding agent is running and select **Edit CLI agent toolbelt**. +* Go to **Settings** > **Agents** > **Third party CLI agents**, then click the **Toolbar layout** preview. + +## Getting started + +Run a supported agent inside Warp — that's it. Warp detects the agent automatically and activates the agent toolbelt with all available features. + +For **agent notifications**, each agent requires a one-time setup — either a notification plugin or a config change. See the individual agent pages for instructions. + +:::note +If you don't see the agent toolbelt, make sure you're on the latest version of Warp. +::: + +--- + +## Related pages + +* [Agent Notifications](/agent-platform/capabilities/agent-notifications/) +* [Tabs](/terminal/windows/tabs/) +* [Tab Configs](/terminal/windows/tab-configs/) diff --git a/src/content/docs/agent-platform/cli-agents/remote-control.mdx b/src/content/docs/agent-platform/cli-agents/remote-control.mdx new file mode 100644 index 0000000..a5f149d --- /dev/null +++ b/src/content/docs/agent-platform/cli-agents/remote-control.mdx @@ -0,0 +1,65 @@ +--- +title: Remote Control +description: >- + Publish any third-party agent session to the cloud so you can monitor + progress, steer the agent, and check in from your phone or another computer. +--- + +Remote Control lets you publish a running third-party agent session — such as Claude Code, Codex, or OpenCode — to the cloud with a single click. Once published, you can monitor progress, review output, and steer the agent from your phone, a web browser, or another computer without staying at the original machine. See [Third-Party CLI Agents](/agent-platform/cli-agents/overview/) for the full list of supported agents. + +This is especially useful for long-running agent tasks. Start a coding agent, publish the session, and check back whenever you want. + +:::note +Remote Control is built on top of [Agent Session Sharing](/agent-platform/local-agents/session-sharing/). It uses the same underlying infrastructure to publish sessions and generate shareable links. +::: + +## Key capabilities + +* **One-click publish** - Click the `/remote-control` chip in the agent utility bar to publish instantly. The shareable link is copied to your clipboard automatically. +* **Monitor from anywhere** - Check on agent progress from a phone, tablet, or another computer — no install required for web viewers +* **Steer remotely** - Send input, approve commands, or redirect the agent without being at your original machine +* **Team access** - Share the link with teammates so they can observe or collaborate on the session +* **Persistent cloud access** - The session stays in sync while it's active. New agent output and terminal activity appear for all viewers in real time. Syncing stops when you close or stop publishing the session. + +## How it works + +When you publish a session through Remote Control, Warp uploads the session state to the cloud and generates a shareable link. The link stays live and in sync — any new agent output, tool use, or terminal activity appears for all connected viewers in real time. You control who can view and who can steer the agent. + +Remote Control differs from standard [Agent Session Sharing](/agent-platform/local-agents/session-sharing/) in its intent: Session Sharing is designed for live collaborative work (pair-programming, interactive debugging), while Remote Control is designed for async monitoring and steering when you're away from your machine. + +## Publishing a session + +1. Start or resume a third-party agent session in Warp (for example, Claude Code or Codex). +2. Click the **`/remote-control`** chip in the agent utility bar. Warp publishes the session to the cloud and copies the shareable link to your clipboard. + +![The /remote-control chip in the agent utility bar with a Start remote control tooltip](../../../../assets/agent-platform/remote-control.png) + +3. A **Sharing link copied** toast notification confirms the link is on your clipboard, and the pane's status icon changes to a red broadcast indicator to show that publishing is active. +4. Open the link on another device, or share it with a teammate. + +To stop publishing, click the **Stop sharing** button in the agent utility bar. The status icon returns to its normal state, confirming the session is no longer accessible remotely. + +## Accessing a remote session + +Published sessions are accessible from: + +* **Web browser** - Open the shared link in any browser. No app install required. +* **Warp desktop app** - Paste the link into Warp on a different machine for the full desktop experience +* **Mobile** - Open the link on your phone or tablet browser to check on progress while away from your desk + +The web experience mirrors the desktop view, showing complete agent activity including thinking steps, tool use, and terminal output. + +## Permissions + +When you publish a session, you control access: + +* **View access** - Anyone with the link can watch the session, see agent output, and review terminal activity +* **Edit access** - You can grant viewers permission to send input, approve commands, or redirect the agent + +Only you (the publisher) can revoke access or stop publishing the session. + +## Related pages + +* [Agent Session Sharing](/agent-platform/local-agents/session-sharing/) +* [Third-Party CLI Agents](/agent-platform/cli-agents/overview/) +* [Viewing Cloud Agent Runs](/agent-platform/cloud-agents/viewing-cloud-agent-runs/) diff --git a/src/content/docs/agent-platform/cli-agents/rich-input.mdx b/src/content/docs/agent-platform/cli-agents/rich-input.mdx new file mode 100644 index 0000000..61233a1 --- /dev/null +++ b/src/content/docs/agent-platform/cli-agents/rich-input.mdx @@ -0,0 +1,51 @@ +--- +title: Rich input editor +description: >- + Warp's rich input editor gives you IDE-style editing, voice input, context + attachment, and slash commands for any supported CLI coding agent. +--- + +Warp's rich input editor lets you write prompts for any CLI coding agent with the same editing experience you'd expect from an IDE — mouse support, context attachment, voice, and more. Press `Ctrl-G` (configurable) or click the **Rich Input** button in the agent utility bar to open it. + +## Key capabilities + +* **IDE-style editing** - Click, select, and navigate your prompt with your mouse. Copy, cut, paste, undo, and word-level navigation all work. Write multi-line prompts with line breaks and soft wrapping. Vim keybindings are also supported. See [Modern text editing](/terminal/editor/) for the full list of shortcuts. +* **Rich context with @mentions** - Reference files, folders, and code symbols with `@` mentions. Attach images for visual context. Search for specific symbols directly from the editor. See [Agent Context](/agent-platform/local-agents/agent-context/) for details. +* **Voice input** - Dictate prompts instead of typing. See [Voice](/agent-platform/local-agents/interacting-with-agents/voice/) for details. +* **Slash commands and skills** - Access saved `/prompts`, `/skills`, and [Warp Drive](/knowledge-and-collaboration/warp-drive/) content with `/`. The editor shows skills specific to the running agent's provider (e.g., Claude-specific skills when running Claude Code). See [Slash Commands](/agent-platform/capabilities/slash-commands/) for details. +* **Agent toolbar** - Browse files, view code changes, and manage the agent session from the toolbar. + +## How to open + +There are two ways to open the rich input editor: + +1. **Keyboard shortcut** - Press `Ctrl-G` (configurable) while a supported agent is running in the active pane. +2. **Rich Input button** - Click the **Rich Input** button in the agent utility bar at the bottom of the pane. + +![The Rich Input button in the agent utility bar at the bottom of the pane](../../../../assets/agent-platform/rich-input-button.png) + +The rich input editor also auto-opens when an agent resumes from a blocked state (for example, after you approve a command). This requires the agent's plugin to be supported and installed. Toggle **Auto show/hide based on agent status** in [Rich input settings](#rich-input-settings) to control this behavior. + +When the rich input editor is active, Warp hides the cursor inside the CLI agent and moves focus to the editor input. Submit your prompt from here and it goes directly to the running agent. + +![The rich input editor open with a prompt being composed](../../../../assets/agent-platform/rich-input-prompt.png) + +## Rich input settings + +In the Warp app, go to **Settings** > **Agents** > **Third party CLI agents** to configure the following: + +* **Auto show/hide based on agent status** - Automatically open the rich input editor when the agent needs input, and hide it when the agent is working. Works with agents that have plugin support and the plugin installed (Claude Code and OpenCode). +* **Auto open on session start** - Automatically open the rich input editor when a CLI agent session starts. +* **Auto dismiss after submission** - Close the editor after you send a prompt. +* **Keyboard shortcut** - The default shortcut is `Ctrl-G`. Customize this in **Settings** > **Keyboard shortcuts**. +* **Disable the Rich Input button** - Right-click the agent utility bar and remove the **Rich Input** chip, or disable the footer entirely in **Settings** > **Agents** > **Third party CLI agents**. + +![Rich input settings panel](../../../../assets/agent-platform/rich-input-settings.png) + +## Related pages + +* [Third-Party CLI Agents Overview](/agent-platform/cli-agents/overview/) +* [Remote Control](/agent-platform/cli-agents/remote-control/) +* [Voice](/agent-platform/local-agents/interacting-with-agents/voice/) +* [Slash Commands](/agent-platform/capabilities/slash-commands/) +* [Agent Context](/agent-platform/local-agents/agent-context/) diff --git a/src/content/docs/agent-platform/cloud-agents/deployment-patterns.mdx b/src/content/docs/agent-platform/cloud-agents/deployment-patterns.mdx new file mode 100644 index 0000000..f2242b0 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/deployment-patterns.mdx @@ -0,0 +1,135 @@ +--- +title: Deployment Patterns +description: >- + Common architectures for deploying cloud agents, including CLI-only, + Oz-hosted, and self-hosted execution patterns. +--- + +Teams adopt cloud agents in a few repeatable ways. This page outlines the most common architectures, what they're good for, and how they fit together. + +#### Quick mental model + +Oz cloud agent setups usually have four moving parts: + +1. **Trigger**: something happens (CI step, webhook, cron, Slack mention). +2. **Orchestration**: something decides what to run and tracks it (Oz orchestrator, GitHub Actions, your internal system). +3. **Execution**: where the agent actually runs (your runner, Oz-hosted environment, or self-hosted workers). +4. **Visibility**: how the team monitors and intervenes (Oz dashboard, session sharing, APIs). + +--- + +### Pattern 1: CLI-only agents (bring your own orchestrator) + +Use this when you already have a system that schedules work (CI, dev boxes, internal orchestrators), and you just need a reliable, cloud-connected agent runner. + +#### What it looks like + +* **Trigger**: GitHub Actions / CI, a script, a dev box action, or an internal orchestrator +* **Orchestration**: your existing system +* **Execution**: wherever that system runs +* **Warp adds**: cloud connectivity, shared context, visibility, session sharing, and tracking + +#### Why teams choose it + +* You want a **drop-in replacement** for other CLI/SDK-based agents (Claude Code, Codex CLI, Gemini CLI/SDK-style flows). +* You want to run agents anywhere without requiring Warp desktop. +* You still want **team-level observability** even when execution is “outside Warp.” + +#### Common examples + +* **CI PR helper**: run formatting checks, generate review comments, suggest fixes, open PRs. +* **Remote dev box agent**: run refactors or debugging tasks inside a pre-provisioned box. +* **Internal orchestrator integration**: treat Warp as one agent option alongside other model providers. + +#### What you still get even without Warp orchestration + +* Access to your shared Warp context (for example MCP config, Warp Drive context, rules/prompts). +* Agent Session Sharing to monitor/steer runs. +* Read-only APIs for tracking and reporting. +* A path to “handoff” workflows (where a run can be continued or inspected in richer surfaces). + +#### Minimal setup checklist + +* A Warp team +* A service account (recommended for automation) +* The Oz CLI installed on the runner / box +* Any needed credentials (often via secrets + environment variables) + +--- + +### Pattern 2: Oz-hosted agents + Oz orchestration (managed cloud execution) + +Use this when you want Oz to run agent workloads on Warp-managed infrastructure, typically inside reproducible Docker environments, with built-in lifecycle management. + +![Warp enterprise SaaS architecture showing customer infrastructure, isolated tenant sandboxes, Warp backend, and LLM providers](../../../../assets/agent-platform/cloud-agents-infra.png) + +#### What it looks like + +* **Trigger**: first-party integrations, cron schedules, API/SDK calls, or on-demand commands +* **Orchestration**: Oz orchestrator +* **Execution**: Oz-hosted environments (Docker-based) +* **Visibility**: Oz dashboard + session sharing + APIs/SDKs + +#### Why teams choose it + +* You want the simplest path to reproducible, scalable cloud execution. +* You want to run many tasks in parallel without building your own sandboxing and scaling layer. +* You want a consistent “production” setup with standardized environments and centralized configuration. + +#### Common ways to trigger + +* **First-party integrations (Slack, Linear, etc.)** that create tasks automatically from external events. +* **Scheduled agents** for recurring work (cron-like automation). +* **Custom triggers** from your own systems using Warp’s API/SDK. +* **On-demand cloud jobs** using CLI commands like oz agent run-cloud. + +#### Example recipe: daily dead-code cleanup + +1. Define an Oz Environment with the repo + toolchain. +2. Create a schedule with a fixed prompt for cleanup. +3. Oz runs the agent on the cadence. +4. Your team monitors runs in the Oz dashboard, reviews artifacts (PRs, plans), and intervenes when needed. + +#### Example recipe: crash triage via Sentry webhook + +1. Define an Oz Environment with the target repo. +2. Register a Sentry webhook to your handler (server, cloud function, Zapier/n8n). +3. Handler extracts crash details, constructs a prompt, and calls the Oz orchestrator API/SDK to start a task. +4. Warp spins up the run in the environment and you monitor progress via UI/API. + +#### Example recipe: fan-out parallel work (sharding) + +If a task is naturally divisible: + +* Launch multiple cloud agents via oz agent run-cloud, each with: + * A shard of the repo (directory/module ownership) + * A shard of the prompt (one responsibility) +* Aggregate results (PRs, notes, plans) in whatever system you prefer. + +#### Example recipe: same task across multiple models + +* Launch N runs with the same prompt, but different profiles that map to different models. +* Compare results and choose the best output (or merge). + +--- + +### Pattern 3: Self-hosted execution + +Use this when you need to control where agent execution happens while still using Oz orchestration and visibility. Repositories are cloned and stored only on your infrastructure; orchestration metadata, session transcripts, and LLM inference route through Warp's backend under [ZDR](/enterprise/security-and-compliance/security-overview/#zero-data-retention-zdr). + +:::note +**Enterprise feature**: Self-hosted execution is available exclusively to teams on an Enterprise plan. +::: + +Self-hosting has two architectures that differ on **who orchestrates agent runs** (both keep code and execution on your infrastructure): + +* **[Managed](/agent-platform/cloud-agents/self-hosting/#managed-architecture)** — Oz orchestrates. You run the `oz-agent-worker` daemon; Oz routes runs to it from Slack, Linear, schedules, the API, or `oz agent run-cloud`. Tasks execute in Docker containers, Kubernetes Jobs, or directly on the host. +* **[Unmanaged](/agent-platform/cloud-agents/self-hosting/unmanaged/)** — You orchestrate. Invoke `oz agent run` directly from your CI, Kubernetes, or dev environment. Warp provides session tracking and observability; it does not start or stop agents. + +Why teams choose self-hosted execution: + +* Code and execution must stay within your network boundary for compliance or security requirements. +* Agents need to access services behind a VPN or self-hosted SCMs like GitLab or Bitbucket. Warp-hosted agents can also access GitLab and Bitbucket over the public internet — see the [GitLab](/agent-platform/cloud-agents/integrations/gitlab/) and [Bitbucket](/agent-platform/cloud-agents/integrations/bitbucket/) setup guides. +* Your environments (multi-service stacks, heavy resource requirements) don't fit in a single Docker container. + +For setup, decision guides, and a quickstart, start with [Self-hosting](/agent-platform/cloud-agents/self-hosting/). diff --git a/src/content/docs/agent-platform/cloud-agents/environments.mdx b/src/content/docs/agent-platform/cloud-agents/environments.mdx new file mode 100644 index 0000000..8725445 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/environments.mdx @@ -0,0 +1,294 @@ +--- +title: Environments +description: >- + Environments ensure your cloud agents run with consistent toolchains across + all triggers. Learn when to use environments and how to configure them. +--- + +Environments ensure your [cloud agents](/agent-platform/cloud-agents/overview/) run with the same toolchain and setup every time, regardless of where they're triggered from. + +An environment defines the execution context for automated agent runs: the **Docker image**, **repositories to clone**, **setup commands**, and **runtime configuration** Warp uses to prepare the workspace before the agent starts. + +:::note +You often don't need an environment for interactive local runs where you’re already in a working checkout and relying on your existing machine setup. +::: + +## Key features + +What environments give you: + +* **Consistent behavior across triggers** – A workflow triggered from Slack behaves identically to one run from Linear or the CLI, using the same toolchain and setup steps every time. +* **One configuration, many uses** – Define your Docker image and setup once, then reuse it across triggers and hosts without duplicating configuration. +* **Full visibility into runs** – Inspect the image, repos, and commands used by a run, making it easy to debug failures or reproduce results. + +:::note +Don't want to bring your own image? Warp provides [prebuilt dev images](https://github.com/warpdotdev/oz-dev-environments) with common languages and tools pre-installed. +::: + +## About environments + +Environments define _how_ an agent runs, not _what_ it does. They're required for [Oz Platform](/agent-platform/cloud-agents/platform/) automation (cloud agents, integrations, API runs) but are not required for interactive local usage. + +An environment typically includes: + +* **Docker image (required)** – The toolchain and runtime the agent runs with. For self-hosted Kubernetes workers, a [`default_image`](/agent-platform/cloud-agents/self-hosting/managed-kubernetes/) on the worker lets you skip creating an environment entirely. +* **Repository/workspace** – One or more repos the agent can clone and operate on. +* **Setup commands** – Commands to prepare the workspace (e.g., dependency install, builds, bootstrapping). + +:::note +Configuring runtime settings: + +* **Environment variables**: Configure these in your Dockerfile using Docker’s \`ENV\` directives or pass them when running the container. +* **Secrets**: For credentials and sensitive data, use [Agent Secrets](/agent-platform/cloud-agents/secrets/). These are configured separately from environments and injected securely at runtime. +::: + +What an environment is not: + +* Host – Hosts determine where execution happens (Warp-hosted vs. self-hosted infrastructure). +* [Agent Profile](/agent-platform/capabilities/agent-profiles-permissions/) – Profiles control agent behavior like permissions, model choice, and defaults, not the runtime environment. +* [Rules](/agent-platform/capabilities/rules/) – Rules determine agent responses and decisions but don't define the container or toolchain. +* [MCP Servers](/agent-platform/cloud-agents/mcp/) – connect agents to external tools and data via MCP. +* Per-run context – Trigger-specific data like Slack threads, PR metadata, or CI logs attach to individual tasks, not the environment configuration. + +## How environments fit into the Oz Platform + +An environment is the runtime layer for automated Oz Platform runs. It defines the container image, repos, and setup steps used when a trigger kicks off an agent task. + +Components in the execution flow: + +1. **Trigger** – An event starts work (Slack mention, Linear comment, CI event, API call) +2. **Task** – Warp creates a tracked task for the run +3. **Environment** – The task uses an environment to define execution context +4. **Host** – The environment runs on a host (Warp-hosted or self-hosted infrastructure). +5. **Agent execution** – The workflow runs in the prepared environment +6. **Outputs** – The run produces PRs, messages, reports, or transcripts + +:::note +**Local agent** runs (using `oz agent run`) don't require an environment. These runs use your current machine's setup. Environments are required for **automated platform** runs like Oz cloud agents and integrations +::: + +### Hosts and environments + +While environments define _how_ an agent runs, hosts determine _where_ the environment executes. + +Host options: + +* **Warp-hosted (default)** – Warp provides the infrastructure. Best for most users who want hands-off execution. +* **[Self-hosted](/agent-platform/cloud-agents/self-hosting/)** – You provide the infrastructure (runners in your cloud or network). Best for compliance requirements, on-premise execution, or custom hardware needs. +* Local (coming soon) – Run environments on your local machine for sandbox development and testing. + +The same environment can run on different hosts with identical behavior. For more details on hosting options, see [Deployment Patterns](/agent-platform/cloud-agents/deployment-patterns/) and [execution hosts](/agent-platform/cloud-agents/platform/#execution-hosts). + +### What happens at runtime + +When you trigger an agent, Warp follows this process: + +1. **Warp receives the trigger.** Warp captures the message content (Slack thread, Linear issue) and any linked context. +2. **Warp creates an execution environment.** Warp spins up an isolated execution context from the Docker image defined in your environment. +3. **Repositories are cloned.** GitHub repositories associated with the environment are cloned into the container. +4. **Setup commands run.** Configured setup commands execute (installing dependencies, running builds, etc.) +5. **The agent workflow runs.** The agent executes the task using the provided context, tools, and permissions. +6. **Results are posted back.** Progress updates, summaries, and results post to the trigger source (Slack, Linear, etc.), or are available in the task transcript. +7. **The container is destroyed.** After completion, the container is torn down. Each run starts from a clean, isolated environment. + +This process ensures every run starts from the same baseline, making results reproducible and debugging straightforward. + +--- + +## When to use environments + +Use an environment when your run needs a predictable toolchain and repeatable setup, regardless of where it’s triggered from. + +* **Integrations and schedules** – Use an environment when runs start from Slack, Linear, GitHub Actions, schedules, or other integrations, and you need consistent behavior each time. +* **CI and remote automation** – Use an environment when the host isn’t consistent (e.g., different runners, varying base images). +* **Team standardization** – Use an environment when you want everyone’s automation runs to use the same image, repos, and setup steps. +* **Toolchain-specific workflows** – Use an environment when the workflow depends on specific language versions, linters, build tools, or system packages. + +**When you can skip an environment** + +You often don’t need an environment for interactive local runs where you’re already in a working checkout and relying on your existing machine setup. + +**Decision checklist** + +Choose an environment if any of the following apply: + +* Runs must be consistent across triggers/hosts. The workflow should behave the same regardless of where it is triggered from. +* The toolchain must be fixed. You need a known image and deterministic setup steps to avoid “it works on my machine” drift. +* The workflow is shared across a team. Multiple people, or systems, will run the workflow and expect repeatable results. + +**Example:** + +If your team tags @Oz in Slack to fix a failing CI job, an environment ensures every run uses the same Docker image, clones the same repos, and runs the same setup commands. + +The fix the agent applies matches what runs in CI and what your teammates see when they review the PR. + +### Where to configure environments + +You can create and configure environments with Warp’s guided setup, or through the CLI. Use the guided flow when you’re first getting started, and use the CLI when you want full control or need to automate environment creation. + +**Before you begin** + +Make sure you have: + +* One or more GitHub repositories that the agent should clone and work in. +* **GitHub authorization configured** so the agent can access your repos. For user-triggered runs, each user authorizes GitHub individually. For automated workflows using team API keys, configure [team GitHub authorization](/agent-platform/cloud-agents/team-access-billing-and-identity/#team-github-authorization) in the Admin Panel. +* A publicly-accessible Docker image that can build and run your code. Official images like [node](https://hub.docker.com/_/node), [python](https://hub.docker.com/_/python), or [rust](https://hub.docker.com/_/rust) work for many projects. You can also use one of [Warp's prebuilt dev images](https://github.com/warpdotdev/oz-dev-environments). + +:::caution +Musl-based Docker images (such as Alpine Linux) are not supported. The agent runtime requires glibc. Use glibc-based images like Debian, Ubuntu, or the default (non-Alpine) variants of official Docker Hub images. +::: + +:::note +Create one environment per codebase, then reuse it across triggers like Slack, Linear, and CLI runs. +::: + +![Creating a new environment in the Oz Web App.](../../../../assets/agent-platform/oz-web-app-new-environment.png) + +### Create an environment with guided setup (recommended) + +Use [`/create-environment`](warp://action/create_environment) when you want Warp to inspect your repos and recommend an environment configuration automatically. This is the fastest way to get started: Warp detects your languages, frameworks, and tools, then suggests appropriate images and setup commands. + +You can run the command inside a Git repo directory with no argument, or with one or more repo paths or URLs. + +```shellscript +# Local file paths +/create-environment ./warp-internal ./warp-server + +# owner/repo +/create-environment warpdotdev/warp-internal warpdotdev/warp-server + +# GitHub URLs +/create-environment +https://github.com/warpdotdev/warp-internal.git +``` + +Warp will: + +* Detect the repositories you want the agent to work with and identify languages, frameworks, and tools +* Look for an existing Dockerfile, recommend an official base image, or help build a custom image (if needed) +* Suggest setup commands based on your scripts and package managers +* Create the environment through the CLI and return an `environment ID` + +This produces a ready-to-use environment that can immediately be connected to integrations and cloud agents. + +### Create an environment with the CLI + +Use the CLI when you already know how you want to configure your environment, you have a custom Docker image you want to use, or when you’re automating environment creation. + +```sh +oz environment create \ + --name <name> \ + --docker-image <image> \ + --repo <owner/repo> \ + --repo <owner/repo> \ + --setup-command "<command1>" \ + --setup-command "<command2>" \ + --description "Optional description" +``` + +Key flags: + +* `--name` (`-n`) — human-readable label for the environment. +* `--docker-image` (`-d`) — image name on Docker Hub. If not specified, you'll be prompted to select from available images (see `oz environment image list`). +* `--repo` (`-r`) — repo to clone (repeatable). +* `--setup-command` (`-c`) — commands run in the order provided (repeatable). +* `--description` — optional description (max 240 characters). + +--- + +## Managing environments + +Once created, you can use the [Oz CLI](/reference/cli/) to inspect and update environments. + +**List environments** + +```sh +oz environment list +``` + +**View an environment’s configuration.** Replace \<ENV\_ID> with the ID of the environment you want to view. + +```sh +oz environment get <ENV_ID> +``` + +**Update an environment** + +Add/remove repos, setup commands, and other properties without recreating the environment. Replace \<ENV\_ID> with the ID of the environment you want to modify. + +```sh +# Add a repo +oz environment update <ENV_ID> --repo owner/repo + +# Remove a repo +oz environment update <ENV_ID> --remove-repo owner/repo + +# Add a setup command +oz environment update <ENV_ID> --setup-command "your command" + +# Remove a setup command (must match exactly) +oz environment update <ENV_ID> --remove-setup-command "exact command" + +# Update the name, description, or Docker image +oz environment update <ENV_ID> --name "new name" +oz environment update <ENV_ID> --description "Updated description" +oz environment update <ENV_ID> --docker-image node:22 +``` + +Additional flags: + +* `--remove-description` — clear the description. +* `--force` — skip confirmation checks for environments used by integrations. + +**Delete an environment.** Replace \<ENV\_ID> with the ID of the environment you want to delete. + +```sh +oz environment delete <ENV_ID> +``` + +Add `--force` to skip confirmation checks for environments used by integrations. + +:::note +For end-to-end setup, see the [Integration setup](/reference/cli/integration-setup/) guide. +::: + +--- + +## Environment design and best practices + +A well-designed environment removes guesswork by giving every run the same starting conditions. When an agent opens a PR from Slack or fixes a failed CI job, the result matches what your team can reproduce locally and in CI. + +**Design guidelines**<br /> + +* **Keep setup repeatable** – Write setup steps that are safe to rerun and that produce the same toolchain and workspace state for a given repo revision. This keeps agent runs reliable across triggers and hosts. +* **Pin versions in the toolchain** – Prefer a Docker or base image that pins language runtimes and core tools, then use lockfiles (\`package-lock.json\`, etc.) for dependencies. +* **Define a clear workspace boundary** – In multi-repo environments, explicitly state which repos are cloned and where setup commands run so the agent doesn’t “guess” the working directory. +* **Make prerequisites explicit** – If the agent must run a build step, generate code, or install system packages before it can do meaningful work, encode that as setup. + +**Example setup commands** + +```sh +# Safer patterns (repeatable and stable) +mkdir -p .cache +npm ci + +# Less safe patterns (can fail on rerun or drift over time) +mkdir .cache +npm install +``` + +:::note +If your setup commands depend on secrets or credentials, configure them through Warp's [secrets mechanism](/agent-platform/cloud-agents/secrets/) rather than hardcoding tokens. +::: + +### Common issues + +* **Setup assumes previous state** – Steps that rely on leftover caches, existing directories, or already-cloned repos can make runs unreliable. + * Solution: Write idempotent setup commands that work on a fresh container. +* **Missing credentials or secrets** – Builds fail when private repos, package registries, or external services require authorization. + * Solution: Configure credentials with [Agent Secrets](/agent-platform/cloud-agents/secrets/). +* **Repo access and GitHub authorization issues** – Runs fail when GitHub doesn't have repo access or the triggering user lacks permissions. + * Solution: See [Integration setup](/reference/cli/integration-setup/#how-github-authorization-works) for GitHub authorization setup. +* **Docker image incompatibility** – You see the error: "VM failed before the agent could run. This is likely an issue with your Docker image." + * Possible cause: Alpine Linux and other musl-based images are not compatible with the agent runtime, which requires glibc. + * Solution: Switch to a glibc-based image such as Debian, Ubuntu, or the default (non-Alpine) variants of official Docker Hub images (e.g. `node`, `python`, `rust`). diff --git a/src/content/docs/agent-platform/cloud-agents/faqs.mdx b/src/content/docs/agent-platform/cloud-agents/faqs.mdx new file mode 100644 index 0000000..2027a9e --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/faqs.mdx @@ -0,0 +1,241 @@ +--- +title: Cloud Agent FAQs +description: >- + Frequently asked questions about cloud agents, including where agents run, + how runs work, supported models, security, and common workflows. +--- + +This page answers common questions about cloud agents, including where they run, how they're configured, and how teams use cloud agents for day-to-day engineering work. + +## Architecture and execution + +### Where do cloud agents run? What's the architecture? + +Agents run either **locally** (inside your Warp session) or **in the cloud** as a **cloud agent run**, inside an **environment** (see [Environments](/agent-platform/cloud-agents/environments/)). + +The cloud agents platform is built around modular, observable execution: + +- A **trigger** starts work (manual, schedule/cron, webhook, or an integration like Slack/GitHub). +- The **agent** executes inside an **environment** (either a Warp-hosted cloud sandbox, or a **self-hosted sandbox** on your infrastructure, depending on plan/support). +- Every step is recorded: **transcripts, tool calls, logs, and outputs**, so work is auditable and debuggable instead of a black box. + +The same agent can be invoked consistently across entry points (Warp conversation, cloud agent web app, the CLI, API/SDK, Slack/GitHub triggers) without rewriting the underlying instructions. + +### What exactly are cloud agents in Warp? + +A **cloud agent** is a packaged automation unit made up of: + +- **Instructions** — A reusable skill/prompt (what it should do). +- **Profile** — Model selection + tools + permissions (how it operates). +- **Trigger** — Manual, cron/schedule, webhook, or integration event (when it starts). +- **Environment** — Repo access, dependencies (Docker image), secrets, setup commands, and runtime config (where it runs). +- **Host** — Local (interactive) or cloud (run), and optionally self-hosted execution (where supported). + +Because the agent definition is modular, the same cloud agent can be started from different surfaces (terminal, web app, CLI, integrations) with a consistent interface. + +### Can we intervene mid-run? + +Yes. For **cloud agent runs**, you can: + +- Inspect **run state**, tool calls, and logs. +- **Steer** the agent while it's running. +- Unblock it with additional instructions or context. + +If you're not happy with where it landed, you can take over to finish the task. That human handoff is a core part of making agents reliable beyond demos. + +### Do cloud agents have access to Codebase Context and indexing? + +Yes. [Codebase Context](/agent-platform/capabilities/codebase-context/) is enabled for all Oz cloud agent runs, as long as Codebase Context is enabled for your account. This includes runs triggered from the CLI, API/SDK, integrations (Slack, Linear, GitHub Actions), and schedules. No additional configuration is needed — if Codebase Context is enabled, cloud agents use it automatically. + +### Can I access a shell inside a cloud agent environment? Are there limitations (Docker, Playwright, etc.)? + +Yes. Cloud agent runs execute in a full Linux environment and behave like a local development session. You can install dependencies, run Docker, and use headless tools like Playwright, subject to standard sandbox resource limits. + +### Do cloud agents support a fully self-hosted, on-prem, or offline mode? + +The cloud agents platform supports self-hosting the **agent sandbox** (the execution environment) on your own infrastructure. The **control plane**—which handles orchestration, tracking, and auditability—remains Warp-managed and is not self-hosted. + +Self-hosted execution is available on **Enterprise** plans. See [Self-Hosting](/agent-platform/cloud-agents/self-hosting/) and [Deployment Patterns](/agent-platform/cloud-agents/deployment-patterns/) for details. + +:::note +[Bring Your Own Key (BYOK)](/support-and-community/plans-and-billing/bring-your-own-api-key/) does not apply to cloud agents. BYOK keys are stored locally on your device and cannot be passed to cloud-hosted or self-hosted agent runs. All cloud agent runs consume [Warp credits](/support-and-community/plans-and-billing/credits/). +::: + +## Models + +### Which models are supported? + +Cloud agents are **multi-model by design**. You can choose models based on cost, latency, and capability, and teams commonly mix models by workflow: + +- Faster/cheaper models for triage and routine tasks. +- Stronger models for complex changes (refactors, multi-file work, deeper reasoning). + +Model choice is configurable per **agent** (and often per environment/workflow), depending on how you set up your profiles. + +### Can I choose which model cloud agents use? + +Yes. Cloud agents support the same set of models available in Warp. Model selection is configurable per agent or environment. + +### Can I authenticate cloud agents with my own ChatGPT or Claude Pro / Max plan? + +We're strong proponents of this, but it ultimately depends on model provider policies. We're actively working with providers to explore whether direct third-party authentication is possible. + +### Do you support local or private LLMs for compliance or air-gapped environments? + +Enterprise plans will support managed integrations like AWS Bedrock and Google Vertex. + +Fully local, offline LLM execution is difficult given the current cloud agents orchestration and runtime architecture, but private-model support via enterprise cloud providers is on the roadmap. + +### Will cloud agents support Agent-to-Agent Protocols (A2A)? + +It’s something we’re actively exploring. Our focus is on building durable orchestration primitives—runs, environments, observability, steering, and coordination—that can support A2A and other emerging standards over time. + +## Security and billing + +### Will cloud storage for agent definitions, runs, and conversations be secure and encrypted? + +Yes. All cloud agent data stored in the cloud is encrypted at rest and in transit, and protected by Warp account–level access controls. + +Cloud agent environments are sandboxed by default, with scoped access to repos, secrets, and compute. Security and isolation are first-class design constraints for the cloud agent runtime. + +### Are cloud agents included in the Build plan, or is it a separate add-on? + +Cloud agents are included in the Build plan. Usage is metered via credits, with pricing based on agent runs and resource consumption. Concurrency limits and credit allocation details are still being finalized. + +### How do cloud agents handle API keys and secrets for agents? + +Secrets are managed via the cloud agents CLI. Secrets are encrypted at rest, scoped to your Warp account, and injected into the agent environment at runtime. They are never hard-coded into agent instructions or logs. + +To learn more about how secrets work in practice, see [Cloud Agent Secrets](/agent-platform/cloud-agents/secrets/). + +## Workflows + +### How do agents handle branching, merge conflicts, and multi-agent coordination with cloud agents? + +The cloud agents platform is intentionally flexible. As the developer, you decide how agents should branch, coordinate, and resolve conflicts. + +Interactive agents can plan work and spawn subagents to parallelize tasks. Cloud agents provide the building blocks for running and coordinating multiple concurrent agents, rather than enforcing a fixed workflow. + +### Why focus on orchestration primitives instead of immediately adopting new agent standards? + +We believe durable infrastructure matters more than transient standards. The cloud agents platform is designed to provide stable building blocks—agent runs, environments, auditability, steering, and coordination—that orchestration frameworks and emerging standards can plug into over time. + +### Can cloud agents integrate with external tools, APIs, or services (like n8n connectors)? + +Yes, and cloud agents do not rely on rigid, predefined workflows. Agents can install CLIs, call external APIs, use MCP servers, and access the internet directly. + +The intent is to delegate flexibility to agents rather than constrain them with fixed connectors. + +### Can I export agent conversations and runs from cloud agents? + +Yes. Conversations can be copied directly from the UI. The cloud agent CLI and API also provide access to full conversation text, logs, and outputs programmatically. + +### How do cloud agents handle environment access, files, and security compared to SSH-based setups? + +Access is handled through Warp session sharing rather than SSH keys. Authentication is tied to Warp accounts and access controls, enabling secure person-to-person sharing. + +Configuration files and credentials can be managed using encrypted .env workflows (for example, dotenv-style encryption), avoiding repeated manual decrypt/encrypt cycles. + +### Can cloud agents review PRs like a teammate? + +Yes. Common patterns for a **cloud agent** in PR review: + +- Summarize changes and intent. +- Flag risky diffs and edge cases. +- Suggest tests and missing coverage. +- Propose refactors for maintainability. + +A typical workflow is: the agent leaves structured review comments and optionally opens a follow-up PR for mechanical fixes (or commits to the branch, if you choose to allow that). + +### Can cloud agents write unit tests? + +Yes, especially when: + +- The repo has a consistent test framework. +- The **environment** is reproducible (dependencies and setup are reliable). + +The strongest loop is: a cloud agent generates tests, runs them in the environment, iterates until green, then opens a PR with the tests plus a short explanation of coverage and assumptions. + +### Can cloud agents do big refactors? + +It can help, but the best practice is to scope into smaller, reviewable chunks. + +Agents are strongest when they can continuously validate progress (tests, lint, typecheck). For large refactors, a staged approach with checkpoints (and possibly multiple subagents for parallel exploration) tends to work better than one giant prompt. + +### Can cloud agents triage issues / tickets automatically? + +Yes. A common cloud agent workflow: + +- When a ticket/issue is created (via integration trigger), a cloud agent gathers context (recent changes, logs/metrics links, ownership). +- Proposes labels/priority and likely causes. +- Drafts next steps or a response. +- Asks clarifying questions back to the reporter when needed. + +### Can cloud agents do dependency upgrades? + +Yes. Scheduled dependency bumps are a classic cloud agent use case: + +- Open a PR. +- Run tests. +- Resolve simple conflicts. +- Attach a risk summary (optional). + +This is usually implemented as a scheduled **cloud agent** producing recurring **runs**. + +### Can cloud agents keep docs up to date? + +Yes. With cloud agents, agents can: + +- Scan for drift (commands that no longer work, onboarding steps that changed). +- Run validations in a docs/test environment. +- Propose doc updates as PRs. + +This is most successful with “docs as code” workflows (GitBook/Mintlify/Docusaurus style), where updates go through normal review. + +## Self-hosting + +### Where does my source code go with self-hosted agents? + +With self-hosting, repositories are cloned and stored only on your infrastructure — Warp never hosts your codebase. Warp uses a split architecture: + +* **Execution plane (your infrastructure)** — Repository clones, build artifacts, runtime secrets, and container filesystem state stay on the machines you control. +* **Control plane (Warp-hosted)** — Session transcripts (which include code context from agent interactions), orchestration metadata, and LLM inference route through Warp's backend under [Zero Data Retention (ZDR)](/enterprise/security-and-compliance/security-overview/#zero-data-retention-zdr) agreements. Warp does not persistently store your source code or use it for model training. + +See [Self-Hosting](/agent-platform/cloud-agents/self-hosting/) for deployment options and [Security Overview](/enterprise/security-and-compliance/security-overview/) for full details. + +### Can I use `oz agent run` in CI or existing runners? + +Yes. The [unmanaged architecture](/agent-platform/cloud-agents/self-hosting/unmanaged/) is designed exactly for this. Run `oz agent run` in any environment where you can execute a CLI command — GitHub Actions, Jenkins, Buildkite, Kubernetes pods, or custom orchestrators. This is how the [`warpdotdev/oz-agent-action`](https://github.com/warpdotdev/oz-agent-action) GitHub Action works. The agent runs locally on the runner and its session is tracked on Warp's backend for observability. + +### Can self-hosted agents access services behind a VPN? + +Yes. Since self-hosted agents run on your infrastructure, they inherit your network access. This means agents can reach self-hosted GitLab/Bitbucket instances, internal APIs, databases, and any other services behind your VPN. This is one of the primary reasons teams choose self-hosting. + +### Does self-hosting work with GitLab or other non-GitHub SCMs? + +Self-hosted agents can use any SCM accessible from your infrastructure. With the [unmanaged architecture](/agent-platform/cloud-agents/self-hosting/unmanaged/), agents run directly on your host and use whatever Git configuration and SCM access is already available. With the [managed architecture](/agent-platform/cloud-agents/self-hosting/#managed-architecture), automatic environment setup currently focuses on GitHub, but you can configure access to other SCMs via volume mounts, environment variables, setup commands, or Kubernetes Secrets (when using the [Kubernetes backend](/agent-platform/cloud-agents/self-hosting/managed-kubernetes/)). See the [GitLab](/agent-platform/cloud-agents/integrations/gitlab/) and [Bitbucket](/agent-platform/cloud-agents/integrations/bitbucket/) setup guides for step-by-step instructions. + +### Do LLM requests still go through Warp with self-hosting? + +Yes. LLM inference routes through Warp's backend, which has [Zero Data Retention (ZDR)](/enterprise/security-and-compliance/security-overview/#zero-data-retention-zdr) agreements with all contracted model providers. Enterprise teams that need full control over inference routing can use [Bring Your Own LLM (BYOLLM)](/enterprise/enterprise-features/bring-your-own-llm/) to route inference through their own cloud provider accounts. BYOLLM currently applies to interactive (local) agents; cloud agent support is coming. + +### What about large monorepos with long environment setup times? + +The [unmanaged architecture](/agent-platform/cloud-agents/self-hosting/unmanaged/) is well-suited for large monorepos because agents run directly in your pre-provisioned environment — there is no Docker image build or repo cloning step. For the [managed architecture](/agent-platform/cloud-agents/self-hosting/#managed-architecture), the Docker backend supports volume mounts (`-v` flag) to mount a pre-existing repo checkout from the host into task containers. With the Kubernetes backend, use `pod_template` to configure persistent volume claims or pre-populated storage for the same purpose. + +:::note +The managed architecture supports three execution backends: **Docker** (default), **Kubernetes**, and **Direct** (no container runtime). The Kubernetes backend runs each task as a Kubernetes Job and includes a Helm chart for deployment. See [Self-Hosting](/agent-platform/cloud-agents/self-hosting/#choosing-a-managed-backend) for details on choosing a backend. +::: + +### Do Kubernetes pods provide enough sandboxing for self-hosted agents? + +This depends on your cluster configuration and risk profile. Evaluate your pod security policies, network policies, and RBAC settings based on your organization's security requirements. + +## Current limitations + +### Do cloud agents support image attachments? + +Cloud agent conversations do not currently support image attachments. Image attachment (via the toolbar button, clipboard paste, or drag-and-drop) is only available in [local agent conversations](/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes/). + +If you need to provide visual context to a cloud agent, you can describe the image contents in your prompt or reference image file paths within the agent's [environment](/agent-platform/cloud-agents/environments/). + diff --git a/src/content/docs/agent-platform/cloud-agents/integrations/azure-devops.mdx b/src/content/docs/agent-platform/cloud-agents/integrations/azure-devops.mdx new file mode 100644 index 0000000..3dccb64 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/integrations/azure-devops.mdx @@ -0,0 +1,128 @@ +--- +title: Azure DevOps +description: >- + Connect Oz cloud agents to Azure DevOps repos using personal access tokens + and Warp-managed secrets. +--- + +Oz cloud agents work with any Git repository, including those hosted on Azure DevOps. A native Azure DevOps integration is not yet available, but you can grant agents access to your repositories using a personal access token and Warp-managed secrets. Once configured, your environment works with any Oz trigger—Slack, Linear, schedules, or the CLI. + +This page explains how to generate an Azure DevOps personal access token, store it securely, and configure a cloud agent environment that clones your repository at runtime. + +:::note +This approach works for both Azure DevOps Services (dev.azure.com) and Azure DevOps Server (self-hosted) instances. +::: + +--- + +## Prerequisites + +* A Warp account ([create an account at oz.warp.dev](https://oz.warp.dev)) +* A repository hosted on Azure DevOps (cloud or self-hosted) +* The [Oz CLI](/reference/cli/) installed and authenticated + +--- + +## Step 1: Generate a personal access token + +1. Sign in to your Azure DevOps organization at `dev.azure.com/{your-org}`. +2. Click the user settings icon (gear) in the top-right corner, then click **Personal access tokens**. +3. Click **+ New Token**. +4. Enter a descriptive name for the token (e.g. `warp-oz-agent`), choose the organization it applies to, and set an expiration date that matches your team's rotation policy. +5. Under **Scopes**, select **Custom defined**, then select **Code** > **Read**. +6. Click **Create**. +7. Copy the token value immediately. Azure DevOps will not show it again. + +:::note +**Code (Read)** is the minimum required scope to clone a repository. If a future workflow requires the agent to push commits or open pull requests, you will also need **Code (Read & Write)**. +::: + +:::note +For Azure DevOps Server (self-hosted), sign in at `https://{server}/{collection}` instead of `dev.azure.com`. The token creation steps are the same. +::: + +--- + +## Step 2: Store the token as a Warp-managed secret + +Warp injects managed secrets as environment variables at runtime and never exposes them in logs or configuration files. See the [Secrets](/agent-platform/cloud-agents/secrets/) documentation for full details on scoping and managing secrets. + +1. Run the following command: + +```bash +oz secret create --team AZURE_DEVOPS_TOKEN +``` + +2. When prompted, paste the token. + +The value is stored and encrypted, and cannot be retrieved after creation. + +:::note +Use `--team` to create a shared token available to all teammates and automated triggers (schedules, Slack, Linear). Use `--personal` if each team member should authenticate with their own Azure DevOps token. Personal secrets work with all triggers and take precedence over a team secret of the same name when both exist. +::: + +If you need to update a secret value, run: + +```bash +oz secret update --team --value AZURE_DEVOPS_TOKEN +``` + +--- + +## Step 3: Create an environment with a clone setup command + +Create an environment that uses your token to clone the repository at the start of each agent run. Because the `--repo` flag in `oz environment create` is designed for GitHub repositories, you clone your Azure DevOps repo via a setup command instead. + +1. Run the following command: + +```bash +oz environment create \ + --name "my-azure-devops-env" \ + --docker-image <image> \ + --setup-command 'git clone https://$AZURE_DEVOPS_TOKEN@dev.azure.com/your-org/your-project/_git/your-repo' \ + --setup-command 'cd your-repo && <install dependencies>' +``` + +:::caution +Use single quotes around setup commands that reference secrets. Double quotes cause your shell to expand `$AZURE_DEVOPS_TOKEN` immediately (to nothing), rather than letting Warp inject the secret at runtime inside the container. +::: + +2. Replace the following placeholders: + * `<image>` with your Docker image (for example, `node:22`, `python:3.12`, or a [Warp prebuilt dev image](https://github.com/warpdotdev/oz-dev-environments)) + * `your-org` with your Azure DevOps organization name + * `your-project` with your Azure DevOps project name + * `your-repo` with your repository name + * For Azure DevOps Server (self-hosted), replace `dev.azure.com` with your server's hostname. + * The second `--setup-command` with any dependency install or build steps your project requires. For example, `npm ci` or `pip install -r requirements.txt`. + +:::caution +Setup commands run on a fresh container for every agent run. Write them to be idempotent — commands that assume existing state (such as a partially cloned repo or a pre-built cache) can fail unpredictably. See [Environment design and best practices](/agent-platform/cloud-agents/environments/#environment-design-and-best-practices) for guidance. +::: + +3. Note the environment ID returned. You will need it in the next step. + +--- + +## Step 4: Test your environment + +Before connecting to integrations, verify the environment works by running a one-off agent. + +1. Run the following command, replacing `<ENV_ID>` with the environment ID from Step 3: + +```bash +oz agent run-cloud --environment <ENV_ID> --prompt "Your task here" +``` + +--- + +## Next steps + +With your environment configured, you can connect it to any Warp trigger exactly as you would with a GitHub-backed environment: + +* **Slack** — Tag **@Oz** in a message to start an agent run against your Azure DevOps repo. See [Slack](/agent-platform/cloud-agents/integrations/slack/). +* **Linear** — Tag **@Oz** on an issue to kick off a workflow. See [Linear](/agent-platform/cloud-agents/integrations/linear/). +* **Scheduled agents** — Run agents on a recurring schedule. See [Scheduled Agents](/agent-platform/cloud-agents/triggers/scheduled-agents/). + +:::note +Native support for opening Azure DevOps pull requests from agent-generated changes is planned as a future enhancement. +::: diff --git a/src/content/docs/agent-platform/cloud-agents/integrations/bitbucket.mdx b/src/content/docs/agent-platform/cloud-agents/integrations/bitbucket.mdx new file mode 100644 index 0000000..d6cde7b --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/integrations/bitbucket.mdx @@ -0,0 +1,208 @@ +--- +title: Bitbucket +description: >- + Connect Oz cloud agents to Bitbucket repos using access tokens and + Warp-managed secrets. +--- + +Oz cloud agents work with any Git repository, including those hosted on Bitbucket. Unlike GitHub, Bitbucket does not have a native Warp integration, but you can grant agents access to your Bitbucket repositories using an access token and Warp-managed secrets. Once configured, your environment works with any Oz trigger—Slack, Linear, schedules, or the CLI. + +This page explains how to generate a Bitbucket access token, store it securely, and configure a cloud agent environment that clones your repository at runtime. + +Bitbucket Cloud and Bitbucket Data Center/Server use different token types: + +* **Bitbucket Cloud** uses **API tokens**, created through your Atlassian Account settings. +* **Bitbucket Data Center/Server** uses **HTTP access tokens**, created through your Bitbucket profile settings. + +Follow the section that matches your setup. + +--- + +## Prerequisites + +* A Warp account ([create an account at oz.warp.dev](https://oz.warp.dev)) +* A repository hosted on Bitbucket (Cloud or Data Center/Server) +* The [Oz CLI](/reference/cli/) installed and authenticated + +--- + +## Bitbucket Cloud + +### Step 1: Generate an API token + +:::note +Bitbucket Cloud API tokens are managed through your Atlassian Account, which is a separate site from bitbucket.org. The following steps will take you there. +::: + +1. Click your avatar in the upper-right corner of Bitbucket, then click **Account settings**. +2. On the Atlassian Account page that opens, click the **Security** tab. +3. Click **Create and manage API tokens**, then click **Create API token with scopes**. +4. Enter a name for the token (e.g. `warp-oz-agent`) and choose an expiration date. +5. Click **Next**. +6. Select **Bitbucket** as the app and click **Next**. +7. Search for `repository` in the **Select Bitbucket scopes** search box, then select **read:repository:bitbucket** (View your repositories). +8. Click **Next**. +9. Click **Create token**. +10. Copy the token value immediately. It is only shown once and cannot be retrieved later. + +:::note +**read:repository:bitbucket** is the minimum required scope to clone a repository. If a future workflow requires the agent to push commits or open pull requests, you will also need **write:repository:bitbucket**. +::: + +--- + +### Step 2: Store the token as a Warp-managed secret + +Warp injects managed secrets as environment variables at runtime and never exposes them in logs or configuration files. See the [Secrets](/agent-platform/cloud-agents/secrets/) documentation for full details on scoping and managing secrets. + +1. Run the following command: + +```bash +oz secret create --team BITBUCKET_API_TOKEN +``` + +2. When prompted, paste the token. + +The value is stored and encrypted, and cannot be retrieved after creation. + +:::note +Use `--team` to create a shared token available to all teammates and automated triggers (schedules, Slack, Linear). Use `--personal` if each team member should authenticate with their own Atlassian account token. Personal secrets work with all triggers and take precedence over a team secret of the same name when both exist. +::: + +If you need to update a secret value, run: + +```bash +oz secret update --value BITBUCKET_API_TOKEN +``` + +--- + +### Step 3: Create an environment with a clone setup command + +Create an environment that uses your token to clone the repository at the start of each agent run. Use the static username `x-bitbucket-api-token-auth` in the clone URL — this is a Bitbucket-specific placeholder that works with API tokens and means you don't need to store your Bitbucket username separately. + +1. Run the following command: + +```bash +oz environment create \ + --name "my-bitbucket-cloud-env" \ + --docker-image <image> \ + --setup-command 'git clone https://x-bitbucket-api-token-auth:$BITBUCKET_API_TOKEN@bitbucket.org/your-workspace/your-repo.git' \ + --setup-command 'cd your-repo && <install dependencies>' +``` + +:::caution +Use single quotes around setup commands that reference secrets. Double quotes cause your shell to expand `$BITBUCKET_API_TOKEN` immediately (to nothing), rather than letting Warp inject the secret at runtime inside the container. +::: + +2. Replace the following placeholders: + * `<image>` with your Docker image (for example, `node:22`, `python:3.12`, or a [Warp prebuilt dev image](https://github.com/warpdotdev/oz-dev-environments)) + * `bitbucket.org/your-workspace/your-repo.git` with your actual repository URL + * The second `--setup-command` with any dependency install or build steps your project requires (for example, `npm ci` or `pip install -r requirements.txt`) + +:::caution +Setup commands run on a fresh container for every agent run. Write them to be idempotent — commands that assume existing state (such as a partially cloned repo or a pre-built cache) can fail unpredictably. See [Environment design and best practices](/agent-platform/cloud-agents/environments/#environment-design-and-best-practices) for guidance. +::: + +3. Note the environment ID returned. You will need it in the next step. + +--- + +## Bitbucket Data Center / Server + +### Step 1: Generate an HTTP access token + +1. Click your profile avatar in Bitbucket, then click **Manage account**. +2. In the left sidebar, click **HTTP access tokens**. +3. Click **Create token**. +4. Enter a name for the token (e.g. `warp-oz-agent`) and choose an expiration date if required by your administrator. +5. Under **Permissions**, choose **Read** for the **Repository** permission. +6. Click **Create token**. +7. Copy the token value immediately. It is only shown once and cannot be retrieved later. + +:::note +**Repository read** is the minimum required permission to clone a repository. If a future workflow requires the agent to push commits, you will also need **Repository write**. +::: + +--- + +### Step 2: Store the token as a Warp-managed secret + +Warp injects managed secrets as environment variables at runtime and never exposes them in logs or configuration files. See the [Secrets](/agent-platform/cloud-agents/secrets/) documentation for full details on scoping and managing secrets. + +1. Run the following command: + +```bash +oz secret create --team BITBUCKET_TOKEN +``` + +2. When prompted, paste the token. + +The value is stored and encrypted, and cannot be retrieved after creation. + +:::note +Use `--team` to create a shared token available to all teammates and automated triggers (schedules, Slack, Linear). Use `--personal` if each team member should authenticate with their own Bitbucket account token. Personal secrets work with all triggers and take precedence over a team secret of the same name when both exist. +::: + +If you need to update a secret value, run: + +```bash +oz secret update --value BITBUCKET_TOKEN +``` + +--- + +### Step 3: Create an environment with a clone setup command + +Create an environment that uses your token to clone the repository at the start of each agent run. + +1. Run the following command: + +```bash +oz environment create \ + --name "my-bitbucket-dc-env" \ + --docker-image <image> \ + --setup-command 'git clone -c "http.extraHeader=Authorization: Bearer $BITBUCKET_TOKEN" https://your-server.com/scm/your-project/your-repo.git' \ + --setup-command 'cd your-repo && <install dependencies>' +``` + +:::caution +Use single quotes around setup commands that reference secrets, so `$BITBUCKET_TOKEN` is expanded at runtime inside the container rather than in your current shell. +::: + +2. Replace the following placeholders: + * `<image>` with your Docker image (for example, `node:22`, `python:3.12`, or a [Warp prebuilt dev image](https://github.com/warpdotdev/oz-dev-environments)) + * `your-server.com/scm/your-project/your-repo.git` with your Bitbucket Data Center/Server repository URL. The `/scm/` path segment is standard for Bitbucket Data Center/Server. + * The second `--setup-command` with any dependency install or build steps your project requires (for example, `npm ci` or `pip install -r requirements.txt`) + +:::caution +Setup commands run on a fresh container for every agent run. Write them to be idempotent — commands that assume existing state (such as a partially cloned repo or a pre-built cache) can fail unpredictably. See [Environment design and best practices](/agent-platform/cloud-agents/environments/#environment-design-and-best-practices) for guidance. +::: + +3. Note the environment ID returned. You will need it in the next step. + +--- + +## Step 4: Test your environment + +Before connecting to integrations, verify the environment works by running a one-off agent. + +1. Run the following command, replacing `<ENV_ID>` with the environment ID from Step 3: + +```bash +oz agent run-cloud --environment <ENV_ID> --prompt "Your task here" +``` + +--- + +## Next steps + +With your environment configured, you can connect it to any Warp trigger exactly as you would with a GitHub-backed environment: + +* **Slack** — Tag **@Oz** in a message to start an agent run against your Bitbucket repo. See [Slack](/agent-platform/cloud-agents/integrations/slack/). +* **Linear** — Tag **@Oz** on an issue to kick off a workflow. See [Linear](/agent-platform/cloud-agents/integrations/linear/). +* **Scheduled agents** — Run agents on a recurring schedule. See [Scheduled Agents](/agent-platform/cloud-agents/triggers/scheduled-agents/). + +:::note +Native support for opening Bitbucket pull requests from agent-generated changes is planned as a future enhancement. +::: diff --git a/src/content/docs/agent-platform/cloud-agents/integrations/cloud-providers.mdx b/src/content/docs/agent-platform/cloud-agents/integrations/cloud-providers.mdx new file mode 100644 index 0000000..641f218 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/integrations/cloud-providers.mdx @@ -0,0 +1,350 @@ +--- +title: Cloud Providers (Preview) +description: >- + Connect Oz cloud agents to your AWS and GCP services. +--- + +Oz cloud agents can securely access cloud providers using short-lived OpenID Connect credentials. + +This page explains how to configure a cloud agent environment to automatically authenticate to your +cloud provider. Oz has built-in support for AWS and GCP, and can work with any provider that +supports OIDC tokens. + +--- + +## Prerequisites + +* A Warp account ([create an account at oz.warp.dev](https://oz.warp.dev)) +* A cloud provider account + +Follow the section for your cloud provider. + +--- + +## AWS + +### Step 1: Create an OIDC identity provider + +The first step is to configure your AWS account to trust OIDC tokens produced by Oz. + +1. Open the AWS IAM console at [https://console.aws.amazon.com/iam](https://console.aws.amazon.com/iam). +2. Click **Identity Providers**, then click **Add provider**. +3. Set the provider type to **OpenID Connect**. +4. Set the **Provider URL** to `https://app.warp.dev`. +5. Set the **Audience** to `sts.amazonaws.com`. +6. Copy the ARN of the new identity provider, which will look like: `arn:aws:iam::<account-id>:oidc-provider/app.warp.dev`. + +:::note +Verify that the provider was created correctly by: +1. Clicking on the `app.warp.dev` link in the list of identity providers. +2. Clicking on **Endpoint verification** +3. Checking that the thumbprint is `08745487e891c19e3078c1f2a07e452950ef36f6` +::: + +--- + +### Step 2: Configure an IAM role + +Next, you will need to set up an AWS IAM role with a trust policy that links it to the OIDC provider. + +1. Open the AWS IAM console at [https://console.aws.amazon.com/iam](https://console.aws.amazon.com/iam). +2. Click **Roles**, then click **Create role**. +3. Select **Custom trust policy**, and fill in the following JSON trust policy: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AllowOzFederation", + "Effect": "Allow", + "Principal": { + "Federated": "<oidc-provider-arn>" + }, + "Action": "sts:AssumeRoleWithWebIdentity", + "Condition": { + "StringEquals": { + "app.warp.dev:aud": "sts.amazonaws.com" + }, + "StringLike": { + "app.warp.dev:sub": "scoped_principal:<team-uid>/*" + } + } + } + ] +} +``` + +You will need to replace: +* `<oidc-provider-arn>` with the ARN of the OIDC provider added in Step 1. +* `<team-uid>` with your Warp team UID. This is the last component of your + [Admin Panel](/enterprise/team-management/admin-panel/) URL. For example, if + the Admin Panel URL is `https://app.warp.dev/admin/abc123def456`, your team UID would be + `abc123def456`. You can also get your team UID from the `oz whoami` command. + +The example above uses `StringLike` with the `scoped_principal:<team-uid>/*` pattern to allow any +user or automation on your team to assume the role. See [the subject claim](#subject-sub) +for the full format of `app.warp.dev:sub`. + +To restrict the role to a specific user, use `StringEquals` +with the fully qualified subject: + +```json +... +"Condition": { + "StringEquals": { + "app.warp.dev:aud": "sts.amazonaws.com", + "app.warp.dev:sub": "scoped_principal:<team-uid>/user:<user-uid>" + } +} +... +``` + +To allow multiple specific principals, use a list of subjects: + +```json +... +"Condition": { + "StringEquals": { + "app.warp.dev:aud": "sts.amazonaws.com", + "app.warp.dev:sub": [ + "scoped_principal:<team-uid>/user:<user-uid-1>", + "scoped_principal:<team-uid>/user:<user-uid-2>", + "scoped_principal:<team-uid>/service_account:<sa-uid>" + ] + } +} +... +``` + +4. Click **Next** and add permissions policies. These policies determine what Oz agents can access + in your AWS account. +5. Click **Next** and enter a role name and optional description. +6. Click **Create role**, then open the role and note down the role ARN. This will be of the form `arn:aws:iam::<account-id>:role/<role-name>`. + +--- + +### Step 3: Enable AWS federation in your cloud agent environment + +Finally, configure the Oz cloud agent environment to use your new AWS role. + +1. Open the Oz web app at [https://oz.warp.dev](https://oz.warp.dev). +2. Create or edit an environment. See [Environments](/agent-platform/cloud-agents/oz-web-app/#environments) for instructions. +3. Expand the **AWS** section and enter the AWS role ARN from Step 2. +4. Save the environment. + +:::caution +Currently, AWS federation can only be configured in the Oz web app, not the CLI. +::: + +Oz agents running in this environment will now automatically assume the configured role when using +the `aws` CLI or a compatible SDK. + +:::note +Oz uses the [**Assume role with web identity**](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html#cli-configure-role-oidc) +AWS authentication mechanism. The following environment variables are set while the agent is running: +* `AWS_ROLE_ARN`: the ARN of the role configured above +* `AWS_WEB_IDENTITY_TOKEN_FILE`: the path to a temporary file containing the agent's Oz OIDC token +* `AWS_ROLE_SESSION_NAME`: a derived session name, of the form `Oz_Run_<run-id>`. +::: + +--- + +## GCP + +### Step 1: Create a Workload Identity Pool and Provider + +The Oz GCP integration uses [Workload Identity Federation](https://docs.cloud.google.com/iam/docs/workload-identity-federation). +You will need to configure a pool and provider to trust OIDC tokens produced by Oz. + +These instructions use the `gcloud` tool. You may also follow the OIDC instructions in +[Configure Workload Identity Federation with other identity providers](https://docs.cloud.google.com/iam/docs/workload-identity-federation-with-other-providers) +to use the GCP console or Terraform. + +1. Create a Workload Identity Pool using the `gcloud` CLI: + +```bash +gcloud iam workload-identity-pools create "<pool-id>" --location=global +``` + +Replace `<pool-id>` with the desired identifier for your pool, such as `oz-agent-pool`. + +2. Create a Provider within the pool: + +```bash +gcloud iam workload-identity-pools providers create-oidc \ + "<provider-id>" \ + --location=global \ + "--workload-identity-pool=<pool-id>" \ + --issuer-uri="https://app.warp.dev" \ + "--attribute-mapping=google.subject=assertion.sub,google.groups=assertion.teams,attribute.environment=assertion.environment" \ + "--attribute-condition='<team-uid>' in assertion.teams" +``` + +Replace `<pool-id>` with the ID you used above, and `<provider-id>` with the desired identifier +for your provider, such as `oz-oidc-provider`. + +Replace `<team-uid>` with the UID of your Warp team. This is the last component of your +[Admin Panel](/enterprise/team-management/admin-panel/) URL. For example, if the admin +panel URL is `https://app.warp.dev/admin/abc123def456`, your team UID would be `abc123def456`. + +:::caution +If you do not set an attribute condition, then _any_ Oz agent will be able to use your Workload +Identity Federation provider, even if they do not belong to your team. +::: + +### Step 2: Configure IAM policies + +You will need to configure IAM policies in GCP that allow Oz agents in the Workload Identity +Federation pool access to resources. + +To give all Oz agents on your team read-only access to all Compute Engine resources in a project, +for example, you would run: + +```bash +gcloud projects add-iam-policy-binding <project-id> \ + --member "principalSet://iam.googleapis.com/projects/<project-number>/locations/global/workloadIdentityPools/<pool-id>/attribute.teams/<team-id>" \ + --role "roles/compute.viewer" +``` + +See [Workload Identity Federation principal types](https://docs.cloud.google.com/iam/docs/workload-identity-federation#principal-types) +for the full syntax supported. + +### Step 3: Enable Workload Identity Federation in your cloud agent environment + +Finally, configure the Oz cloud agent environment to use your Workload Identity Federation provider. + +1. Open the Oz web app at [https://oz.warp.dev](https://oz.warp.dev). +2. Create or edit an environment. See [Environments](/agent-platform/cloud-agents/oz-web-app/#environments) for instructions. +3. Expand the **GCP** section and enter the project number, pool ID, and provider ID from Step 1. +4. Save the environment. + +:::caution +Currently, Workload Identity Federation can only be configured in the Oz web app, not the CLI. +::: + +Oz agents running in this environment will now automatically configure +[Application Default Credentials](https://docs.cloud.google.com/docs/authentication/application-default-credentials) +to use the configured pool. Both the `GOOGLE_APPLICATION_CREDENTIALS` and `CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE` +environment variables are set, so both the `gcloud` CLI and official Google SDKs will use the Oz +federated credentials. Oz uses +[**executable-sourced credentials**](https://docs.cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#create-credential-config) +to configure ADC for automatic token rotation. + +## Other providers + +To authenticate from Oz to another provider that supports OIDC federation, you can issue tokens +directly. + +Within the agent environment, use the `oz federate issue-token` command to produce an OIDC token +with your provider as the audience: + +```bash +oz federate issue-token --audience your-provider.com --output-format json +``` + +Optionally, add `--duration <duration>` to customize the token validity. This cannot exceed the +maximum runtime of an Oz agent. + +You may then exchange this token for provider-specific credentials. + +## OIDC token claims + +All Oz OIDC tokens include standard claims like `iss` (issuer) and `iat` (issued at). + +### Audience + +The `aud` claim will reflect the default for your cloud provider. For AWS, this is always +`sts.amazonaws.com`. For GCP, it is derived from the Workload Identity Federation provider, +such as `https://iam.googleapis.com/projects/<project-number>/locations/global/workloadIdentityPools/<pool-id>/providers/<provider-id>`. + +### Subject (`sub`) + +The `sub` claim is set to the identity that an Oz agent is executing as. This will either be a +Warp user ID or an autogenerated account ID for team-scoped agent runs. + +By default, the `sub` claim uses the format `<principal-type>:<principal-id>`: +* `user:abc123def456`: Identifies a user with ID `abc123def456` +* `service_account:abc123def456`: Identifies your autogenerated team account + +When authenticating to AWS, Oz will use a different `sub` claim format, because AWS trust policies cannot +match on custom OIDC claims. The format above will be prefixed with your team UID: +* `scoped_principal:xyz789/user:abc123def456`: Identifies the user `abc123def456`, who is a member of team `xyz789`. +* `scoped_principal:user:abc123def456`: Identifies the user `abc123def456`, who is not on any team. +* `scoped_principal:xyz789/service_account:abc123def456`: Identifies the autogenerated account for team `xyz789`. + +In addition, user OIDC tokens include an `email` claim with the user's email address. + +To get possible user ID values, use the `oz whoami` command: + +```bash +oz whoami +User ID: abc123 +Email: user@warp.dev +Team ID: xyz789 +Team Name: My Team +``` + +You can also check the user IDs from past runs using the Oz API: + +```bash +curl https://app.warp.dev/api/v1/agent/runs -H "Authorization: Bearer $WARP_API_KEY" +{ + "runs": [ + { + ... + "creator": { + "type": "user", + "uid": "<user-id>", + "display_name": "User Name", + "email": "user@warp.dev" + } + } + ] +} +``` + +### Team + +Every token includes a `teams` claim. The value will be a list with your team UID - currently, this +list only ever contains a single value. + +### Oz run + +The following claims are derived from an Oz agent run: + +* `run_id`: the unique identifier for the individual run. This is not suitable for configuring + access, but is useful to log for debugging. +* `environment`: the unique identifier for the agent's [Environment](/agent-platform/cloud-agents/environments/). +* `agent_name`: the name of the [Skill](/agent-platform/cloud-agents/skills-as-agents/) that the agent was invoked with. +* `skill_spec`: the canonical identifier for the skill, such as `github-org/github-repo:.warp/skills/skill-name/SKILL.md`. +* `host`: the execution host. This will either be `warp`, for Warp-hosted agents, or the worker ID if [self-hosting](/agent-platform/cloud-agents/self-hosting/). + +### Example token + +The following OIDC token references an Oz agent running as a specific Warp user: + +```json +// JWT Header +{ + "typ": "JWT", + "alg": "ES256", + "kid": "<example-key-id>" +} +// JWT Payload +{ + "aud": ["sts.amazonaws.com"], + "sub": "user:<example-user-id>", + "email": "user@warp.dev", + "teams": ["<example-team-id>"], + "run_id": "<example-id>", + "environment": "<example-id>", + "agent_name": "<example-name>", + "skill_spec": "<example-spec>", + "host": "warp", + "iss": "https://app.warp.dev", + "jti": "<example-id>", + "exp": 1775210175, + "iat": 1775206575, + "nbf": 1775206575 +} diff --git a/src/content/docs/agent-platform/cloud-agents/integrations/demo-issue-triage-bot.mdx b/src/content/docs/agent-platform/cloud-agents/integrations/demo-issue-triage-bot.mdx new file mode 100644 index 0000000..f6eb4b9 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/integrations/demo-issue-triage-bot.mdx @@ -0,0 +1,27 @@ +--- +title: "Demo: Issue Triage Bot" +description: >- + A walkthrough demo showing how to trigger a cloud agent from a GitHub Action + to automatically triage bug reports and create draft pull requests. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +<VideoEmbed url="https://www.youtube.com/watch?feature=youtu.be&v=dK2eohQ2Yow" /> + +:::note +Example repository: [**https://github.com/warpdotdev/warp-agents-demo-github-issue-triage**](https://github.com/warpdotdev/warp-agents-demo-github-issue-triage) +::: + +In this demo, Ben shows how to trigger Warp’s coding agent from a GitHub Action to automate bug report handling as soon as issues hit your repository. + +* The workflow acts like a maintainer-first “front door” for bugs: it evaluates whether a report is actionable, asks for missing details when it isn’t, and escalates directly into a draft pull request when it is + +**The first half focuses on triage.** + +* The agent reads the issue (and optionally your repo’s bug report template) and returns a simple ready/not-ready decision. +* If the report is missing key context like a clear description or reproduction steps, the workflow automatically posts a friendly comment requesting the missing info and applies a “needs info” label for maintainers to track. + +**The second half extends the workflow into investigation + fix.** + +* When a report has sufficient detail, Ben shows the agent investigating the codebase, implementing a fix, adding tests, running verification, and returning a PR-ready summary. +* The GitHub Action then commits the changes and opens a draft PR that follows the repo’s pull request template and links back to the original issue for review. diff --git a/src/content/docs/agent-platform/cloud-agents/integrations/github-actions.mdx b/src/content/docs/agent-platform/cloud-agents/integrations/github-actions.mdx new file mode 100644 index 0000000..2b89bbd --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/integrations/github-actions.mdx @@ -0,0 +1,222 @@ +--- +title: GitHub Actions +description: >- + Run Oz agents in GitHub Actions to automate code review, issue triage, and + CI fixes. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Run Oz agents directly in your GitHub Actions workflows using `oz-agent-action`. The agent integrates seamlessly into your CI pipeline, automating tasks like code review, issue triage, bug fixing, and maintenance using your repository context and GitHub permissions. This page covers how the integration works, how to set it up, and common automation patterns for development teams. + +:::note +**Getting started?** See the [GitHub Actions quickstart](/agent-platform/cloud-agents/integrations/quickstart-github-actions/) to set up your first workflow, or visit the [oz-agent-action repository](https://github.com/warpdotdev/oz-agent-action) for detailed setup instructions and ready-to-use workflow templates. +::: + +Watch this demo to see the integration in action: + +<VideoEmbed url="https://www.loom.com/share/534f88b6a98e43ca9769ca09de6424b5" /> + +In this demo + +* Automated PR reviews with both summary feedback and inline suggestions +* One-click batching and committing of agent suggestions directly from the GitHub UI +* Automatically fixing failing CI checks by opening a suggested PR +* Suggesting fixes for small review comments (“nits”) without checking out code locally + +--- + +### What the GitHub Actions integration does + +The `oz-agent-action` is a GitHub Action that wraps the Oz CLI and: + +* Runs an Oz agent inside an Actions job +* Caches package installation for faster builds +* Captures the agent's output for use in subsequent workflow steps +* Lets you pass workflow context, event data, and previous step outputs into the agent prompt +* Allows the agent to comment on PRs, post results, or open branches via the GitHub CLI +* Supports inline code suggestions that can be batched and committed directly from the GitHub pull request UI +* Enables using pre-built skills or custom skills for specialized tasks + +### Requirements + +To use Oz agents in GitHub Actions, you need: + +* A [**Warp API Key**](/reference/cli/#generating-api-keys) stored as a [GitHub secret](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions) — this authenticates the agent with Warp +* Workflow permissions that match your intended actions (for example, `pull-requests: write` if the agent should commit or comment on PRs) — the agent performs actions on your behalf using the GitHub token available to the workflow +* The `oz-agent-action` step added to your workflow +* **For private repositories using `@oz-agent` mention workflows**: The [`oz-agent`](https://github.com/oz-agent) GitHub user must be [invited as a member](https://docs.github.com/en/organizations/managing-membership-in-your-organization/inviting-users-to-join-your-organization) of your GitHub organization (see [Responding to comments with @ mentions](#1-responding-to-comments-with--mentions) for details) +* Familiarity with GitHub Actions concepts — see the official docs for [GitHub Actions](https://docs.github.com/en/actions) + +### Using Skills + +Skills provide reusable instructions for Oz agents. You can use pre-built skills from the [oz-skills repository](https://github.com/warpdotdev/oz-skills) or create custom [skills](/agent-platform/capabilities/skills/) for your specific workflows. Skills can also be deployed as [standalone agents](/agent-platform/capabilities/skills/#skills-as-agents) to run on a schedule or in response to events. + +#### How to use skills + +You can specify a skill using the `skill` input parameter, either instead of or in combination with prompts: + +```yaml +- name: Run agent with a skill + uses: warpdotdev/oz-agent-action@v1 + with: + skill: 'code-review' + warp_api_key: ${{ secrets.WARP_API_KEY }} +``` + +#### Skill format options + +The `skill` parameter supports multiple formats for referencing skills: + +* **`skill_name`** - Searches for the skill in your repository's skill directories +* **`repo:skill_name`** - Uses a skill from a specific repository +* **`org/repo:skill_name`** - Uses a skill from a specific organization's repository + +#### Combining skills with prompts + +You can combine skills with prompts to provide specialized context while customizing the specific task: + +```yaml +with: + skill: 'code-review' + prompt: 'Focus on security vulnerabilities in authentication code' + warp_api_key: ${{ secrets.WARP_API_KEY }} +``` + +In this example, the `code-review` skill provides the base context and approach for code review, while the prompt narrows the focus to security concerns in authentication code. + +:::note +Skills help maintain consistency across your workflows and can encapsulate best practices for common tasks like code review, issue triage, or automated testing. +::: + +--- + +## Common use cases + +The `oz-agent-action` supports several automation patterns commonly used in CI. + +### 1. Responding to comments with @ mentions + +* **File**: [`examples/respond-to-comment.yml`](https://github.com/warpdotdev/oz-agent-action/blob/main/examples/respond-to-comment.yml) +* **Use case**: Add "@oz-agent fix this typo" or similar comments to a PR or Issue. + +What it does: + +* Listens for comments containing a trigger phrase +* Sends the comment and thread context into the agent +* Agent replies directly to the comment +* If code changes are requested, the agent commits fixes to the PR branch + +**When to use:** + +* Interactive coding assistance during review or issue triage. + +:::note +**Private repositories require org membership for `@oz-agent`** + +If your repository is in a **private GitHub organization**, you must [invite the `oz-agent` user](https://docs.github.com/en/organizations/managing-membership-in-your-organization/inviting-users-to-join-your-organization) as a member of your organization before using `@oz-agent` mention workflows. Without this: + +* `@oz-agent` will not appear in GitHub's autocomplete when writing comments. +* Comments containing `@oz-agent` will not trigger the workflow, because GitHub does not recognize the mention. + +This is a GitHub platform limitation for private organizations — any user must be an org member to be mentioned in comments on private repos. + +Public repositories are not affected by this requirement. +::: + +### 2. Automated pull request review + +* **File**: [`examples/review-pr.yml`](https://github.com/warpdotdev/oz-agent-action/blob/main/examples/review-pr.yml) +* **Use case**: Provide automated agent feedback when a PR is opened or marked ready for review. + +What it does: + +* Automatically runs when PRs open or switch to “ready for review” +* Agent inspects changed files, analyzes the diff, and comments inline +* Optionally posts a summary comment + +**When to use:** + +* Fast initial review before human reviewers step in. + +### 3. Automatically fix issues + +* **File**: [`examples/auto-fix-issue.yml`](https://github.com/warpdotdev/oz-agent-action/blob/main/examples/auto-fix-issue.yml) +* **Use case**: Apply the `oz-agent` label on an Issue to trigger automated fixes. + +What it does: + +* Detects when the label is added +* Agent analyzes the issue description and repo context +* Creates a PR with a fix (fix/issue-NUMBER) +* Or comments explaining why automation wasn’t possible + +**When to use:** + +* Automating bug fixes, small features, or maintenance tasks. + +### 4. Daily issue summaries + +* **File**: [`examples/daily-issue-summary.yml`](https://github.com/warpdotdev/oz-agent-action/blob/main/examples/daily-issue-summary.yml) +* **Use case**: Scheduled summaries of newly opened issues. + +What it does: + +* Runs daily at 09:00 UTC +* Fetches issues created in the past 24 hours +* Generates a categorized summary +* Sends the summary to Slack via webhook + +**When to use:** + +* Daily visibility into new work across your repositories. + +### 5. Fixing failing CI checks + +* **File**: [`examples/fix-failing-checks.yml`](https://github.com/warpdotdev/oz-agent-action/blob/main/examples/fix-failing-checks.yml) +* **Use case**: Automatically attempt fixes when a workflow or test suite fails. + +What it does: + +* Triggers when specified CI workflows fail +* Pulls failure logs +* Attempts to diagnose and fix the root cause +* Opens a PR with the fix and comments with a link + +**When to use:** + +* Reducing downtime from failing builds or flaky tests. + +### 6. Suggest fixes for review comments + +* **File**: [`examples/suggest-review-fixes.yml`](https://github.com/warpdotdev/oz-agent-action/blob/main/examples/suggest-review-fixes.yml) +* **Use case**: Automatically propose code suggestions for small, actionable review comments such as typos, naming tweaks, and minor refactors. + +**What it does:** + +* Triggers when a pull request review is submitted +* Fetches review comments and stores them in review\_comments.json +* Sends comments and context to an agent to decide which ones are simple, actionable fixes +* Generates `responses.json` with explanations and suggestion blocks for each fixable comment +* Replies inline to the original review comments with the generated suggestions + +**When to use:** + +* Quickly addressing straightforward review feedback such as typos, naming tweaks, style nits, and small refactors. + +--- + +## Troubleshooting + +### `@oz-agent` mention doesn't trigger the workflow + +If you're tagging `@oz-agent` in a PR or issue comment and the workflow doesn't run: + +1. **Check org membership (private repos only)**: In private organizations, the `oz-agent` GitHub user must be a [member of your organization](https://docs.github.com/en/organizations/managing-membership-in-your-organization/inviting-users-to-join-your-organization). Without this, GitHub won't recognize the mention and the `issue_comment` event won't match the workflow trigger. Ask an org admin to invite [`oz-agent`](https://github.com/oz-agent) via **Settings > People > Invite member**. +2. **Verify the workflow file**: Ensure your workflow is on the default branch and the trigger condition matches `@oz-agent` (e.g. `contains(github.event.comment.body, '@oz-agent')`). +3. **Check workflow permissions**: The workflow must have the appropriate permissions (e.g. `issues: read`, `pull-requests: write`) to respond. + +### `@oz-agent` doesn't appear in GitHub autocomplete + +GitHub only suggests users who are members of the organization when typing `@` in comments on private repositories. [Invite `oz-agent`](https://docs.github.com/en/organizations/managing-membership-in-your-organization/inviting-users-to-join-your-organization) to your organization to make it appear in autocomplete. + +Note: Even if `@oz-agent` doesn't autocomplete, you can still type the mention manually — but the workflow will only trigger if the user is an org member (for private repos). diff --git a/src/content/docs/agent-platform/cloud-agents/integrations/gitlab.mdx b/src/content/docs/agent-platform/cloud-agents/integrations/gitlab.mdx new file mode 100644 index 0000000..f971e97 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/integrations/gitlab.mdx @@ -0,0 +1,127 @@ +--- +title: GitLab +description: >- + Connect Oz cloud agents to GitLab repos using personal access tokens and + Warp-managed secrets. +--- + +Oz cloud agents work with any Git repository, including those hosted on GitLab. Unlike GitHub, GitLab does not have a native Warp integration, but you can grant agents access to your GitLab repositories using a personal access token and Warp-managed secrets. Once configured, your environment works with any Oz trigger—Slack, Linear, schedules, or the CLI. + +This page explains how to generate a GitLab personal access token, store it securely, and configure a cloud agent environment that clones your repository at runtime. + +:::note +This approach works for both GitLab.com and self-hosted GitLab instances. +::: + +--- + +## Prerequisites + +* A Warp account ([create an account at oz.warp.dev](https://oz.warp.dev)) +* A repository hosted on GitLab (cloud or self-hosted) +* The [Oz CLI](/reference/cli/) installed and authenticated + +--- + +## Step 1: Generate a personal access token + +:::note +These steps generate a personal access token tied to your GitLab account. If your team prefers a shared bot user, [GitLab project access tokens](https://docs.gitlab.com/user/project/settings/project_access_tokens/) work the same way. +::: + +1. Sign in to GitLab. +2. Click your avatar in the top-right corner, then click **Edit profile**. +3. In the left sidebar, click **Access**, then click **Personal access tokens**. +4. Click **Add new token**. +5. Enter a descriptive name for the token (e.g. `warp-oz-agent`), and choose an expiration date that matches your team's rotation policy. +6. Under **Select scopes**, select **read\_repository**. +7. Click **Generate token**. +8. Copy the token value immediately. GitLab will not show it again. + +:::note +**read\_repository** is the minimum required scope to clone a repository. If a future workflow requires the agent to push commits or open merge requests, you will also need **write\_repository**. +::: + +--- + +## Step 2: Store the token as a Warp-managed secret + +Warp injects managed secrets as environment variables at runtime and never exposes them in logs or configuration files. See the [Secrets](/agent-platform/cloud-agents/secrets/) documentation for full details on scoping and managing secrets. + +1. Run the following command: + +```bash +oz secret create --team GITLAB_TOKEN +``` + +2. When prompted, paste the token. + +The value is stored and encrypted, and cannot be retrieved after creation. + +:::note +Use `--team` to create a shared token available to all teammates and automated triggers (schedules, Slack, Linear). Use `--personal` if each team member should authenticate with their own GitLab token. Personal secrets work with all triggers and take precedence over a team secret of the same name when both exist. +::: + +If you need to update a secret value, run: + +```bash +oz secret update --value GITLAB_TOKEN +``` + +--- + +## Step 3: Create an environment with a clone setup command + +Create an environment that uses your token to clone the repository at the start of each agent run. Because the `--repo` flag in `oz environment create` is designed for GitHub repositories, you clone your GitLab repo via a setup command instead. + +1. Run the following command: + +```bash +oz environment create \ + --name "my-gitlab-env" \ + --docker-image <image> \ + --setup-command 'git clone https://oauth2:$GITLAB_TOKEN@gitlab.com/your-group/your-repo.git' \ + --setup-command 'cd your-repo && <install dependencies>' +``` + +:::caution +Use single quotes around setup commands that reference secrets. Double quotes cause your shell to expand `$GITLAB_TOKEN` immediately (to nothing), rather than letting Warp inject the secret at runtime inside the container. +::: + +2. Replace the following placeholders: + * `<image>` with your Docker image (for example, `node:22`, `python:3.12`, or a [Warp prebuilt dev image](https://github.com/warpdotdev/oz-dev-environments)) + * `gitlab.com/your-group/your-repo.git` with your actual repository URL + * For a self-hosted GitLab instance, replace `gitlab.com` with your server's hostname. + * The second `--setup-command` with any dependency install or build steps your project requires. For example, `npm ci` or `pip install -r requirements.txt`. + +:::caution +Setup commands run on a fresh container for every agent run. Write them to be idempotent — commands that assume existing state (such as a partially cloned repo or a pre-built cache) can fail unpredictably. See [Environment design and best practices](/agent-platform/cloud-agents/environments/#environment-design-and-best-practices) for guidance. +::: + +3. Note the environment ID returned. You will need it in the next step. + +--- + +## Step 4: Test your environment + +Before connecting to integrations, verify the environment works by running a one-off agent. + +1. Run the following command, replacing `<ENV_ID>` with the environment ID from Step 3: + +```bash +oz agent run-cloud --environment <ENV_ID> --prompt "Your task here" +``` + +--- + +## Next steps + +With your environment configured, you can connect it to any Warp trigger exactly as you would with a GitHub-backed environment: + +* **Slack** — Tag **@Oz** in a message to start an agent run against your GitLab repo. See [Slack](/agent-platform/cloud-agents/integrations/slack/). +* **Linear** — Tag **@Oz** on an issue to kick off a workflow. See [Linear](/agent-platform/cloud-agents/integrations/linear/). +* **Scheduled agents** — Run agents on a recurring schedule. See [Scheduled Agents](/agent-platform/cloud-agents/triggers/scheduled-agents/). + +:::note +Native support for opening GitLab merge requests from agent-generated changes is planned as a future enhancement. +::: diff --git a/src/content/docs/agent-platform/cloud-agents/integrations/index.mdx b/src/content/docs/agent-platform/cloud-agents/integrations/index.mdx new file mode 100644 index 0000000..2ede48d --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/integrations/index.mdx @@ -0,0 +1,106 @@ +--- +title: Integrations Overview +description: >- + Configure Warp's first-party integrations by creating environments, + connecting GitHub, and enabling agents to run your code and automate + development workflows. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Warp integrations let your team trigger agents directly from the terminal, or from tools like [Slack](/agent-platform/cloud-agents/integrations/slack/) and [Linear](/agent-platform/cloud-agents/integrations/linear/). Once set up, agents can: + +* Read conversation or issue context +* Run code inside your codebase in a remote environment +* Open pull requests and perform other multi-step agent workflows on your behalf + +:::note +For a full walkthrough of Warp's integrations and configurable environments, please refer to [Integration setup](/reference/cli/integration-setup/). +::: + +All of this is powered by the [Oz CLI](/reference/cli/). + +--- + +## Quickstart + +The fastest way to get agents running from Slack or Linear is to create an environment with the guided flow. An **environment** defines everything the agent needs to run your code remotely, including your Docker image, repos, and setup commands. + +<VideoEmbed url="https://www.youtube.com/watch?v=ahFfInVD0HQ" /> + +#### 1. Run /create-environment + +From Warp, run the following slash command: + +``` +/create-environment +``` + +You can run it inside any repo, or point it at multiple repos: + +``` +/create-environment ./frontend ./backend +/create-environment your-org/repo-name +/create-environment https://github.com/your-org/api.git +``` + +:::note +Learn more about slash commands and how to use them in the [Slash Commands](/agent-platform/capabilities/slash-commands/) documentation. +::: + +The guided flow will: + +* Detect which repos you want the agent to work with +* Identify languages, frameworks, and tools +* Suggest a Docker image (or build/push one if needed) + * The Docker image can be your own custom image, an official base image (e.g. node, python), or one of Warp's prebuilt dev images (see [repo](https://github.com/warpdotdev/oz-dev-environments)). +* Recommend setup commands +* Create the environment and return an environment ID + +This produces a ready-to-use environment that Warp can use across Slack, Linear, and terminal triggers. + +#### 2. Authorize GitHub + +Warp will prompt you to install or update the Warp GitHub app so the agent can read and write to the repos you included. You only need to do this once. Teammates will authorize on their first run as needed. + +:::note +**Using Azure DevOps, GitLab, or Bitbucket?** Native integrations for these platforms are not yet available, but you can connect repositories by storing a personal access token as a Warp-managed secret and cloning via a setup command. See [Azure DevOps](/agent-platform/cloud-agents/integrations/azure-devops/), [GitLab](/agent-platform/cloud-agents/integrations/gitlab/), or [Bitbucket](/agent-platform/cloud-agents/integrations/bitbucket/) for step-by-step instructions. +::: + +#### 3. Create an integration + +:::note +For easier setup, use the [Oz web app](/agent-platform/cloud-agents/oz-web-app/) at [oz.warp.dev](https://oz.warp.dev) to configure integrations with a guided flow. The web app works on mobile devices. +::: + +Alternatively, use the CLI: + +For Slack: + +``` +oz integration create slack --environment <ENV_ID> +``` + +For Linear: + +``` +oz integration create linear --environment <ENV_ID> +``` + +The CLI opens an authorization page where you install Oz into your Slack workspace or Linear team. + +#### 4. Start using agents + +In Slack: + +* Tag **@Oz** in a message or thread +* Or DM the bot + +In Linear: + +* Tag @Oz on an issue + +Warp will read the thread/issue, spin up your environment, run the workflow in the cloud, and post progress + PRs back into the same conversation. + +--- + +For more details on configuring integrations and environments in Warp, please refer to [Integration setup](/reference/cli/integration-setup/). diff --git a/src/content/docs/agent-platform/cloud-agents/integrations/linear.mdx b/src/content/docs/agent-platform/cloud-agents/integrations/linear.mdx new file mode 100644 index 0000000..275723a --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/integrations/linear.mdx @@ -0,0 +1,129 @@ +--- +title: Linear +description: >- + Automate Linear issues with Oz agents that run code in the cloud and create + pull requests on your behalf. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +The Linear integration lets your team delegate development work directly to agents from inside Linear. When you tag @Oz on an issue or comment, an agent will spin up in the cloud, clone the repos defined in your environment, and begin working through the task. + +Agents keep you updated inside Linear, generate pull requests using your GitHub account, and provide a link to join a live remote session so you can watch or steer the workflow in real time. + +<VideoEmbed url="https://youtu.be/FNefNmbSdmg?si=PxvDuW6OfNZBvhSl" /> + +This guide explains what the integration does, how it works end-to-end, and how to configure it for your Warp team. + +--- + +### Using Oz inside Linear + +Tagging @Oz on an issue or in a Linear comment starts an agent run. Oz clones the repositories defined in your environment, sets up your development environment using your Docker image and setup commands, and begins working through the task with full context from your codebase and the Linear issue. Agents post updates as they progress, including a task list, elapsed time, and checkpoints, so you can follow along without leaving Linear. + +Agents also share a link to an interactive remote session using Warp's [cloud agent session sharing](/agent-platform/cloud-agents/viewing-cloud-agent-runs/). Opening this link lets you view the live terminal output for the running agent in Warp or in the browser. From there, you can interrupt or guide the agent with additional instructions when needed. Once the agent finishes, it will create a pull request on your behalf — using your GitHub permissions — and post a summary of its work and the PR link back into Linear. + +You can start an agent in two ways: + +* **Tag @Oz in a comment** and describe what you want done. +* **Assign the issue to Oz** as if it were a teammate. + +Oz will acknowledge the request directly in the Linear issue and begin working. + +Agents keep you informed through: + +* **Activity updates** inside Linear +* A **running task list** and timeline showing what the agent is working on +* A **shared session link** that opens a live view of the agent’s cloud environment + +Session sharing works in Warp or in a browser view and allows multiple teammates to watch the session. + +![Live cloud agent session shared from a Linear issue, viewed in Warp on Web.](../../../../../assets/agent-platform/linear-warp-on-web.png) + +#### Joining the remote session + +Selecting [**Open in Warp**](/agent-platform/cloud-agents/viewing-cloud-agent-runs/) (or the web option) opens the active session. You'll see: + +* The agent’s full execution log +* The plan pane with the task list +* An input box to add clarifying instructions +* A real-time view identical to a local Warp task + +Any instructions you give will interrupt the agent, feed the new context, and resume work. + +When the task is complete: + +* Warp commits the changes using your GitHub identity +* A pull request is created through the GitHub CLI +* The PR includes a clean title and description based on the Linear issue and the agent’s work +* A summary and link to the PR appear in the Linear issue + +Because PRs are created as _you_, this makes code review, auditing, and team collaboration straightforward. + +--- + +### Requirements + +* **Team membership** - The Linear integration requires you to be part of a [Warp team](/knowledge-and-collaboration/teams/). Teams can be created on any plan, including Free. +* **Plan and credits** - Your team must be on a plan that supports integrations (Build, Max, or Business) and have at least 20 credits available (any type of Warp credits work). See [Access, Billing, and Identity](/agent-platform/cloud-agents/team-access-billing-and-identity/) for details. +* **Infrastructure** - By default, agents run on Warp-hosted infrastructure. Enterprise teams can [self-host agents](/agent-platform/cloud-agents/self-hosting/) on their own infrastructure. +* **Identity** - You must be logged into Warp with the same email as your Linear workspace. +* **GitHub authorization** - You must authorize the Warp GitHub app the first time you trigger an agent. + * The repositories involved must be included in your environment and accessible to the Warp GitHub app. + * You must have write access to the repo if you want Warp to create PRs on your behalf. + +--- + +### How to configure the integration + +Setup involves two steps powered by the [Oz CLI](/reference/cli/). For more instructions, see [Integrations Overview](/agent-platform/cloud-agents/integrations/). + +#### 1. Create an environment + +An environment defines everything the agent needs to run your code: + +* A **Docker image** (public on Docker Hub) +* A set of **GitHub repos** the agent should clone +* Optional **setup commands** that run before the agent starts + +You can create an environment via: + +* The CLI +* The guided flow using `/create-environment` ([Slash Commands](/agent-platform/capabilities/slash-commands/)) + +For full instructions, see our [Environment Setup](/agent-platform/cloud-agents/integrations/) docs. + +#### 2. Create the Linear integration + +Once your environment exists, create the integration. + +:::note +For easier setup, use the [Oz web app](https://oz.warp.dev) to configure integrations with a guided flow. +::: + +Alternatively, you can use the CLI: + +``` +oz integration create linear --environment <ENV_ID> +``` + +The CLI will open a browser window prompting you to install the Oz app into your Linear workspace. After installation, the integration becomes available to all members of your Warp team. + +--- + +### Uninstallation instructions + +To remove the Oz integration from Linear: + +1. Only a Linear team admin can manage app permissions. +2. In Linear, go to **Settings**. +3. Navigate to Agents under the Features section. +4. Select Oz from the list of installed agents. +5. Click **Revoke access** to remove the integration for your workspace. + +<VideoEmbed url="https://www.loom.com/share/2f1648586d8148dc80561c00a09ca334" /> + +After revoking access, Warp will no longer be able to read issues, receive triggers, or create updates in Linear. If you reinstall later, you’ll need to authorize Warp again during setup. + +### Troubleshooting + +If something isn't working as expected—missing repos, PR failures, Linear not detecting Oz, or environment issues—see our [Integrations Troubleshooting](/agent-platform/cloud-agents/integrations/#troubleshooting) page for detailed guidance on GitHub permissions, environment configuration, and common setup problems. diff --git a/src/content/docs/agent-platform/cloud-agents/integrations/quickstart-github-actions.mdx b/src/content/docs/agent-platform/cloud-agents/integrations/quickstart-github-actions.mdx new file mode 100644 index 0000000..8e22e22 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/integrations/quickstart-github-actions.mdx @@ -0,0 +1,92 @@ +--- +title: GitHub Actions quickstart +description: >- + Set up your first Oz agent in GitHub Actions in ~10 minutes. Run agents as + workflow steps to automate code review and issue triage. +--- + +Add Oz agents to your GitHub Actions workflows with [`oz-agent-action`](https://github.com/warpdotdev/oz-agent-action). This quickstart walks you through setting up your first GitHub Actions integration: a PR review workflow that automatically analyzes pull requests and posts inline review comments. + +--- + +## Prerequisites + +* **Warp API key** - In the Warp app, click your profile photo, then go to **Settings** > **Cloud platform** > **Oz Cloud API Keys** to create one. Use a personal key if the agent needs to write to your repo. See [API Keys](/reference/cli/api-keys/) for details. +* **A GitHub repository with Actions enabled** - The workflow file will live in `.github/workflows/` in your repo. + +--- + +## 1. Add your API key as a GitHub Actions secret + +Store your Warp API key as a GitHub Actions secret so workflows can authenticate without exposing the key in your code. + +1. In your repository on GitHub, go to **Settings** > **Secrets and variables** > **Actions**. +2. Click **New repository secret**. +3. Set the name to `WARP_API_KEY`. +4. Paste your API key into the **Secret** field. +5. Click **Add secret**. + +## 2. Create the workflow file + +This workflow triggers an Oz agent whenever a PR is opened or marked ready for review. The agent reviews the diff and posts inline comments. + +Create `.github/workflows/oz-pr-review.yml` in your repository with the following content: + +```yaml +name: Oz PR review + +on: + pull_request: + types: [opened, ready_for_review] + +permissions: + contents: read + pull-requests: write + +jobs: + review: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Review PR with Oz + uses: warpdotdev/oz-agent-action@v1 + with: + prompt: | + Review the code changes on this pull request: + 1. Use `git diff origin/${{ github.base_ref }}...HEAD` to identify changes. + 2. Analyze the diff for style, security, or correctness issues. + 3. Use `gh pr review --comment` to post inline suggestions. + warp_api_key: ${{ secrets.WARP_API_KEY }} +``` + +This workflow listens for pull request events and runs the `oz-agent-action` step, which executes the prompt to review code changes. Commit and push this file to your default branch to activate the workflow. + +## 3. Open a pull request + +Create a new pull request in your repository to trigger the workflow. + +To verify the workflow ran: + +1. Go to the **Actions** tab in your repository. +2. Click **Oz PR review** in the list of workflows. +3. Select the most recent run to see the agent's output in the job logs. + +## 4. View the run + +Each `oz-agent-action` step creates a cloud agent run you can inspect from the Oz dashboard: + +* **Oz web app** - Go to [oz.warp.dev/runs](https://oz.warp.dev/runs) to see the full run transcript: status, commands executed, files changed, and agent output. See [Viewing Cloud Agent Runs](/agent-platform/cloud-agents/viewing-cloud-agent-runs/) for a complete walkthrough. +* **Warp app** - Open the conversations panel to see the run alongside your other agent activity. + +When the run completes, the agent posts feedback as inline review comments on the PR. + +**Breaking it down:** The agent runs in Warp's cloud infrastructure — not on GitHub's runners — using the workflow's GitHub token for repository access. Each run is isolated, tracked, and auditable, just like any manually triggered cloud agent run. + +--- + +## Next steps + +* **Explore more workflow patterns** - The [oz-agent-action repository](https://github.com/warpdotdev/oz-agent-action) includes ready-to-use consumer workflow templates for responding to `@oz-agent` comments, auto-fixing labeled issues, daily issue summaries, fixing failing CI checks, and suggesting review fixes. Copy any template from `consumer-workflows/` into `.github/workflows/` in your repo. +* **Use skills for reusable behavior** - Replace the inline `prompt` with a `skill` parameter to apply consistent, version-controlled instructions across all your CI workflows. See [Skills](/agent-platform/capabilities/skills/). +* **Read the full reference** - [GitHub Actions](/agent-platform/cloud-agents/integrations/github-actions/) covers all action inputs, output handling, session sharing for debugging, and troubleshooting. diff --git a/src/content/docs/agent-platform/cloud-agents/integrations/quickstart.mdx b/src/content/docs/agent-platform/cloud-agents/integrations/quickstart.mdx new file mode 100644 index 0000000..d3b2d3f --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/integrations/quickstart.mdx @@ -0,0 +1,79 @@ +--- +title: Integrations quickstart +description: >- + Trigger your first Oz agent from Slack in ~15 minutes and get results + in-thread. +--- + +Oz integrations let you trigger cloud agents directly from the tools your team already uses. This guide walks you through connecting Oz to Slack. Once set up, anyone on your team can tag @Oz in a message or thread to kick off a cloud agent that runs the task and posts results back to the conversation. + +:::note +**Want to connect with Linear instead?** The setup is the same — just substitute `slack` with `linear` in the CLI commands, or select Linear in the Oz web app. See [Linear](/agent-platform/cloud-agents/integrations/linear/) for details. +::: + +--- + +## Prerequisites + +* **Eligible plan** - The Slack integration requires a Warp team on Build, Max, or Business plan with at least 20 credits available. See [Access, Billing, and Identity](/agent-platform/cloud-agents/team-access-billing-and-identity/). +* **An Oz cloud environment** - Agents run inside a configured environment that includes repos and other dependencies. If you don't have one yet, follow the [Cloud Agents Quickstart](/agent-platform/cloud-agents/quickstart/) or run `/create-environment` in Warp. +* **GitHub authorization** - Warp needs access to your repos to clone code and open PRs. You'll be prompted to authorize the Warp GitHub app when you first create the integration. + +--- + +## 1. Connect the Slack integration + +The simplest way to set up the integration is **using the Oz web app**: + +1. Navigate to the Oz web app at [oz.warp.dev/integrations](https://oz.warp.dev/integrations). +2. Click **Slack**. +3. Follow the guided flow to select your environment and authorize Oz in your Slack workspace. + +All members of your Warp team can now use the integration. + +**Using the Oz CLI instead:** + +Run `oz integration create` to connect the Slack integration: + +```bash +oz integration create slack --environment <ENV_ID> +``` + +Replace `<ENV_ID>` with your environment ID (see [Environments](/agent-platform/cloud-agents/environments/) if you need to create one). Find it with `oz environment list` on the Oz CLI or in the [Oz web app](https://oz.warp.dev). The CLI opens a browser window to authorize the Oz app in your workspace. + +To attach a default prompt that applies to every agent run triggered from this integration, add the `--prompt` flag: + +```bash +oz integration create slack \ + --environment <ENV_ID> \ + --prompt "Always open a draft PR and request review from the team-leads group." +``` + +## 2. Tag @Oz in Slack + +In any channel or thread in your Slack workspace, tag @Oz with a task: + +> @Oz scan the authentication module for security issues and summarize what you find + +Oz acknowledges the request immediately and starts an agent run in the cloud. You'll see progress updates appear in the thread as the agent works. + +You can also tag @Oz inside an existing thread. Oz picks up the full thread history as context automatically, so you can tag it mid-discussion without repeating background. + +## 3. Watch the run + +While the agent works, progress updates appear directly in the Slack thread. To inspect the run in more detail: + +* **Click the session link** - Oz posts a link in the thread to open a live terminal view of the agent. Watch in real time, add follow-up instructions, or let it run to completion. +* **Go to [oz.warp.dev/runs](https://oz.warp.dev/runs)** - See the full run transcript: status, commands executed, files changed, and agent output. See [Viewing Cloud Agent Runs](/agent-platform/cloud-agents/viewing-cloud-agent-runs/) for a complete walkthrough. + +When the task is complete, Oz posts a summary back to the original Slack thread. + +**Breaking it down:** Oz reads the Slack thread as context, runs the agent inside the environment you configured — with your repos cloned and Docker image running — and returns results where the conversation started, in Slack, without anyone leaving the thread. + +--- + +## Next steps + +* **Customize agent behavior** - Use a [skill](/agent-platform/cloud-agents/skills-as-agents/) as the base prompt for your integration to give Oz consistent, reusable instructions across every run. +* **Trigger agents programmatically** - Use the [API & SDK](/reference/api-and-sdk/) to build custom automations and integrations on top of Oz agents. +* **Read the full Slack reference** - [Slack](/agent-platform/cloud-agents/integrations/slack/) covers identity mapping, team access, monitoring runs, troubleshooting, and uninstall instructions. diff --git a/src/content/docs/agent-platform/cloud-agents/integrations/slack.mdx b/src/content/docs/agent-platform/cloud-agents/integrations/slack.mdx new file mode 100644 index 0000000..707ab2e --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/integrations/slack.mdx @@ -0,0 +1,176 @@ +--- +title: Slack +description: >- + Trigger Oz agents from Slack to run cloud tasks, track progress, and create + pull requests. +--- + +### Overview + +The Slack integration lets your team trigger agents directly from conversations in Slack. When you tag **@Oz** in a message or DM the bot, Warp will start an agent in the cloud, clone the repositories defined in your environment, and begin working through the task with full context from your codebase and the Slack thread. + +Agents keep you updated as they work, generate pull requests using your GitHub account, and share a link to a live remote session so you can watch or guide the workflow in real time. + +This page explains what the integration does, how it behaves inside Slack, and how to configure it for your Warp team. + +--- + +### Using Oz inside Slack + +Tagging @Oz in a message or thread starts an agent run. The agent clones the repositories in your environment, sets up your development environment using your Docker image and setup commands, and begins working with the context from the Slack conversation. Oz posts updates back into the thread as it progresses so you can follow along without opening your terminal. + +Agents also share a link to an interactive remote session using Warp's [cloud agent session sharing](/agent-platform/cloud-agents/viewing-cloud-agent-runs/). Opening this link gives you a live terminal view of the cloud agent running your code. You can interrupt or steer the agent by providing additional instructions, and the agent will pick up where it left off with the new context. + +When the work is complete, Warp will create a pull request on your behalf using your GitHub permissions and send a summary and PR link back to the original Slack thread. + +### Triggering an agent + +You can start an agent in three ways: + +* **Tag @Oz in a channel message** + + Describe the task, and Oz will begin working with full context from the thread. +* **Tag @Oz inside a thread** + + Oz will automatically collect the thread's prior messages and use them as context. +* **DM Oz directly** + + Useful for private tasks or experimentation. + +Oz will acknowledge the request in Slack and start running the task immediately. + +### Monitoring agent progress + +Agents keep you informed directly in Slack via: + +* Activity updates showing progress throughout the run +* An evolving task list and timeline +* Checkpoints indicating major steps completed +* A direct link to the Oz run in the [Oz web app](/agent-platform/cloud-agents/oz-web-app/), where you can view the full run transcript and metadata +* A session-sharing link that opens a live terminal view of the remote agent + +[Cloud agent session sharing](/agent-platform/cloud-agents/viewing-cloud-agent-runs/) works in Warp or in your browser and supports multiple teammates joining the same live session. + +### Joining the live remote session + +Selecting `View agent` opens the active agent session. Inside the session you’ll see: + +* The agent’s full execution log +* The plan/task list +* Real-time output just like a local Warp task +* An input box for follow-up instructions + +Any instruction you type will interrupt the agent, incorporate the new guidance, and then resume execution. This is the best way to debug or steer multi-step tasks. + +### Pull requests and output + +Once the agent finishes, it will: + +* Commit changes using your GitHub account +* Create a pull request via the GitHub CLI +* Generate a clean title and description referencing your Slack request +* Post the summary and PR link directly into the Slack thread + +Because PRs are created as you, the workflow slots seamlessly into your team’s existing review process. + +--- + +### Requirements + +* **Team membership** - The Slack integration requires you to be part of a [Warp team](/knowledge-and-collaboration/teams/). Teams can be created on any plan, including Free. +* **Plan and credits** - Your team must be on a plan that supports integrations (Build, Max, or Business) and have at least 20 credits available (any type of Warp credits work). See [Access, Billing, and Identity](/agent-platform/cloud-agents/team-access-billing-and-identity/) for details. +* **Infrastructure** - By default, agents run on Warp-hosted infrastructure. Enterprise teams can [self-host agents](/agent-platform/cloud-agents/self-hosting/) on their own infrastructure. +* **Identity** - You must be logged into Warp with the same email used in your Slack workspace. +* **GitHub authorization** - You must authorize the **Warp GitHub app** the first time you trigger a Slack integration request. + * The repositories involved must be included in your environment and accessible to the Warp GitHub app. + * You must have write access for Warp to open PRs on your behalf. + +### How to configure the Slack integration + +Setup involves two steps, powered by the [Oz CLI](/reference/cli/). + +#### 1. Create an environment + +An environment defines everything the agent needs to run your code in the cloud: + +* A Docker image (public on Docker Hub) +* The GitHub repos the agent should clone +* Optional setup commands that run before the agent starts + +Create an environment via: + +* **Oz CLI** + +```bash +oz environment create \ + --name <name> \ + --docker-image <image> \ + --repo <owner/repo> \ + --setup-command "<command>" +``` + +* **Guided setup using `/create-environment`** ( [Slash Commands](/agent-platform/capabilities/slash-commands/)) + + This flow analyzes your repos, recommends a Docker image, suggests setup commands, and can build + push a custom image if needed. + +See the [Environment Setup](/agent-platform/cloud-agents/integrations/) docs for detailed instructions. + +#### 2. Create the Slack integration + +Once your environment is ready, create the integration. + +:::note +For easier setup, use the [Oz web app](https://oz.warp.dev) to configure integrations with a guided flow. +::: + +Alternatively, use the CLI: + +``` +oz integration create slack --environment <ENV_ID> +``` + +The CLI will open a browser window to install the Oz app into your Slack workspace. After installation, the integration becomes available to all members of your Warp team. + +You can optionally attach a custom prompt that is applied to every agent run: + +``` +oz integration create slack \ + --environment <ENV_ID> \ + --prompt "Always prefix PR titles with '[WARP]' and include detailed test steps." +``` + +### Identity mapping and team access + +* Integrations are scoped to your Warp team. +* Any teammate in the same Slack workspace and Warp team can use the integration. +* Warp maps Slack users to Warp accounts by email address. +* Teammates must individually authorize GitHub on their first run. + +--- + +### Uninstallation instructions + +To remove the Oz app from your Slack workspace: + +1. Open Slack and go to **Apps** in the left sidebar. +2. Search for Oz. +3. Select the app, then open the **About** tab. +4. Click **Configuration**. This will open your workspace’s app configuration page in the browser. +5. Scroll to the bottom and select **Remove App**. +6. Confirm the removal. + +![Warpy is just an internal Slackbot, your Warp slackbot should be called Oz.](../../../../../assets/agent-platform/delete-warpy.png) + +![Confirmation dialog to remove the Oz app from a Slack workspace.](../../../../../assets/agent-platform/remove-slack-app.png) + +Once removed, Slack will immediately disable the integration for all teammates. + +### Troubleshooting + +If something isn't working—missing repos, Slack not detecting @Oz, PR failures, or environment configuration issues—see the [Integrations Troubleshooting](/agent-platform/cloud-agents/integrations/#troubleshooting) page. It covers: + +* GitHub authorization and repo access +* Docker image pull errors +* Environment visibility +* Email and identity mismatches +* Integration installation issues diff --git a/src/content/docs/agent-platform/cloud-agents/managing-cloud-agents.mdx b/src/content/docs/agent-platform/cloud-agents/managing-cloud-agents.mdx new file mode 100644 index 0000000..fdab182 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/managing-cloud-agents.mdx @@ -0,0 +1,96 @@ +--- +title: Managing Cloud Agents +description: >- + Monitor and manage cloud agent activity across your team with Warp's + centralized management view, including filtering, status tracking, and + session inspection. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Warp provides a centralized management view where you can monitor agent activity across your account and (where applicable) your team. You can access this view in the Warp app or through the [Oz web app](/agent-platform/cloud-agents/oz-web-app/) at [oz.warp.dev](https://oz.warp.dev), which works on mobile devices. + +The management view is designed to answer, at a glance: + +* Which agents have been running recently (and what's running right now) +* Which runs succeeded, failed, or were canceled +* Where an agent run was triggered from (a local agent conversation, the Oz CLI, Slack, etc.) +* How many credits those runs consumed + +<VideoEmbed url="https://www.loom.com/share/679c267ddd2d44519abf79edcb1122c7" /> + +This management view includes your **local (interactive) agents** and [cloud agent](/agent-platform/cloud-agents/overview/) runs. + +![Warp's management view showing interactive and cloud agent runs.](../../../../assets/agent-platform/management-view-scannable-list.png) + +### What appears in the management view + +The management view includes two categories of agent activity. + +#### Interactive agents + +* Initiated from the Warp desktop app. +* The conversation is owned by you. It opens locally in Warp, and can be shared via a link when needed. +* Credit usage reflects inference. + +#### Cloud agent runs + +* Background executions initiated by triggers such as integrations and automations (for example: Slack, Linear, schedules, GitHub Actions, or API/CLI invocations). +* Each run produces a shared session that can be inspected after completion (including logs, messages, and outputs). +* Credit usage reflects inference + compute, shown as a single combined value in this view. + +:::caution +All usage rolls up into Warp's standard [**credit**](/support-and-community/plans-and-billing/credits/) system. +::: + +In the **Personal** tab, you can view all of the interactive and cloud agent conversations that you own. In the **All** tab, you can see everything from the personal tab, as well as any cloud agent sessions that are shared with you by your teammates; right now, this only includes things triggered from integrations. + +--- + +### The agents list + +Each row represents a single item in the management view (either an interactive conversation or a cloud agent run). The list is intended to be scannable: you should be able to understand “what happened” without opening anything. + +#### Fields you’ll see + +**Source** + +Where the agent was launched from. Common sources include: + +* **Interactive:** an [agent conversation](/agent-platform/local-agents/overview/) started in the Warp app +* **CLI**: a local run triggered by the [Oz CLI](/reference/cli/) +* **API**: a run triggered by [Warp's API](/reference/api-and-sdk/) +* **Slack / Linear**: runs triggered by [integrations](/agent-platform/cloud-agents/integrations/) +* **Scheduled**: runs triggered on a [cron schedule](/agent-platform/cloud-agents/triggers/scheduled-agents/) + +**Status** + +Warp uses a small set of statuses to help you quickly identify what needs attention: + +<table><thead><tr><th width="173.375">Status</th><th width="78.41973876953125">Icon</th><th>Description</th></tr></thead><tbody><tr><td><code>Working</code></td><td>N/A</td><td>in progress (may include queued / running states)</td></tr><tr><td><code>Blocked</code></td><td>🟨</td><td><p><em>(interactive only)</em></p><p><br />the conversation is waiting on user input or a required step</p></td></tr><tr><td><code>Canceled</code></td><td>⬜️</td><td>(interactive only)<br /><br />the interactive conversation was canceled before completion</td></tr><tr><td><code>Failed / Errored</code></td><td>🔺</td><td>something went wrong (applies to both interactive and cloud agent runs)</td></tr><tr><td><code>Success</code></td><td>✅</td><td>completed successfully (applies to both interactive and cloud agent runs)</td></tr></tbody></table> + +**Duration (for cloud agent tasks)** + +* Shown for cloud agent runs to indicate how long the task executed. +* Note: Interactive conversations generally don’t map cleanly to a single “run duration,” so this is currently omitted. + +--- + +### Inspecting an agent + +**The primary interaction is simple:** + +* Clicking a cloud agent row opens the [shared session](/agent-platform/cloud-agents/viewing-cloud-agent-runs/) for that run (logs/messages/output). +* Clicking an interactive row opens the conversation locally in the Warp app. + +This makes the management view a navigation surface: find the thing you care about, click once, and you’re in the right context to inspect or continue work. + +### Filtering + +In both _Personal_ and _All_ views, you can open the filter menu and filter by: + +* Source (interactive, API, CLI, Slack/Linear, scheduled) +* Day of creation +* Creator +* Status + +This is the fastest way to isolate "everything that failed today," "runs from Slack," or "what a specific teammate triggered via integrations." diff --git a/src/content/docs/agent-platform/cloud-agents/mcp.mdx b/src/content/docs/agent-platform/cloud-agents/mcp.mdx new file mode 100644 index 0000000..4374c3b --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/mcp.mdx @@ -0,0 +1,118 @@ +--- +title: MCP Servers +description: >- + Connect cloud agents to external tools, APIs, and internal services using + MCP servers. +--- + +Cloud agents can call external tools through [Model Context Protocol (MCP) servers](/agent-platform/capabilities/mcp/). This lets agents reach beyond the terminal to automatically interact with systems like GitHub, dbt, Sentry, or any custom internal service, whenever the workflow requires it. + +## When to use MCP servers + +Add MCP servers to a cloud agent when it needs to: + +* Read from or write to an external API (issue trackers, monitoring tools, cloud services) +* Call local processes that expose MCP endpoints +* Use internal developer tools that you've wrapped in an MCP interface + +The agent calls MCP tools automatically based on what the task requires, without the need for explicit instruction. + +## How MCP configuration works + +You can supply MCP configuration in two ways: + +* **At run time** — pass `--mcp` when calling `oz agent run` or `oz agent run-cloud`. See [MCP Servers](/reference/cli/mcp-servers/) in the CLI reference for the full syntax. +* **In an agent config file** — define `mcp_servers` directly in a YAML or JSON agent config file (passed with `-f / --file`). This is the recommended approach for repeatable workflows. + +## Configuration schema + +Each MCP server entry is keyed by a name you choose. A server config must have **exactly one** transport type: + +| Transport | Field(s) | When to use | +|-----------|----------|-------------| +| Warp-shared server | `warp_id` | Reference an MCP server already configured in Warp by its UUID | +| Stdio (local process) | `command`, `args` | Launch a local executable as an MCP server | +| Streamable HTTP / SSE | `url` | Connect to a remote or locally hosted MCP endpoint | + +### Supported fields + +* **`warp_id`** — UUID of a Warp-shared MCP server (find UUIDs with `oz mcp list` or from **Settings** > **Agents** > **MCP servers**) +* **`command`** — Executable to launch (stdio transport) +* **`args`** — Arguments passed to `command` (only valid with `command`) +* **`env`** — Environment variables passed to the process (only valid with `command`) +* **`url`** — HTTP or HTTPS endpoint URL (streamable HTTP or SSE transport) +* **`headers`** — HTTP headers sent with requests (only valid with `url`) + +You may define any number of MCP servers in a single config. + +### Example configuration + +```json +{ + "github": { + "url": "https://mcp.example.com/github" + }, + "dbt": { + "command": "uvx", + "args": ["dbt-mcp"], + "env": { + "DBT_HOST": "https://example.us1.dbt.com", + "DBT_SERVICE_TOKEN": "${DBT_SERVICE_TOKEN}" + } + } +} +``` + +## Using MCP servers in an agent config file + +For repeatable cloud agent workflows, declare your MCP servers inside the agent config file passed to `-f / --file`: + +```json +{ + "name": "my-production-agent", + "model_id": "claude-sonnet-4", + "system_prompt": "You are a helpful assistant focused on backend development.", + "environment_id": "SVhg783GBFQHk1OfdPfFU9", + "mcp_servers": { + "github": { + "url": "https://mcp.example.com/github" + }, + "dbt": { + "command": "uvx", + "args": ["dbt-mcp"], + "env": { + "DBT_HOST": "https://example.us1.dbt.com", + "DBT_SERVICE_TOKEN": "${DBT_SERVICE_TOKEN}" + } + } + } +} +``` + +Pass this file when running a cloud agent: + +```sh +oz agent run-cloud --environment <ENV_ID> -f my-agent-config.json --prompt "Check for regressions in the last deploy" +``` + +## Requirements and defaults + +* MCP configuration must be valid JSON, or YAML when embedded in a broader agent config file. +* If `mcp_servers` is omitted, the agent runs with no MCP servers enabled. +* Each server name must be unique and non-empty. +* The `warp_id` transport is validated against your Warp account. Referenced servers must be accessible to you. + +## Limitations + +:::caution +Warp does not currently support OAuth-based MCP servers for cloud agents. This means MCP servers that require browser-based authentication, like some hosted Figma configurations, cannot be used directly. + +As a workaround, you can pass Figma mockups as **image context** to the agent, which can then build and test UI against those images. +::: + +## Learn more + +* [MCP Servers (CLI reference)](/reference/cli/mcp-servers/) — how to pass MCP configuration using the `--mcp` flag +* [Model Context Protocol (MCP)](/agent-platform/capabilities/mcp/) — configuring MCP servers in Warp for local agents +* [Environments](/agent-platform/cloud-agents/environments/) — set up the runtime context (repo, image, startup commands) for cloud agent tasks +* [Secrets](/agent-platform/cloud-agents/secrets/) — store and inject credentials into agent runs safely diff --git a/src/content/docs/agent-platform/cloud-agents/overview.mdx b/src/content/docs/agent-platform/cloud-agents/overview.mdx new file mode 100644 index 0000000..ff4689c --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/overview.mdx @@ -0,0 +1,154 @@ +--- +title: Cloud Agents Overview +description: >- + Run background agents in the cloud from events, schedules, or integrations + with team-wide observability. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Oz Cloud Agents are **cloud-connected**, **background agents** that run on the [Oz Platform](/agent-platform/cloud-agents/platform/). + +**New to cloud agents?** Start with the [Cloud Agents Quick Start](/agent-platform/cloud-agents/quickstart/) to run your first cloud agent in ~10 minutes. + +<VideoEmbed url="https://youtu.be/poLkJhO7fdo" /> + +### What cloud agents are designed for + +Cloud agents are designed for situations where: + +* **You need agents to react to system events.** + * Examples include crashes, bug reports, Slack interactions, cron timers, or CI steps. +* **You want observability into agent activity across a team or system.** + * This includes being able to see what ran, when it ran, and what it did. +* **You need more parallelism than local execution typically allows.** + * For example, running many agent tasks concurrently in the cloud, sharding a repo-wide task into multiple runs, or fanning out the same task across multiple targets. +* **You want agents to operate continuously as part of engineering infrastructure.** + * This includes scheduled maintenance tasks and integration-driven automation. + +![Oz use cases across the development lifecycle: Plan, Prototype, Build, Validate, Review + Merge, Deploy + Monitor](../../../../assets/agent-platform/oz-use-cases.png) + +--- + +### What is a cloud agent run? + +A cloud agent run is represented as an agent task. A task is created when a trigger fires (for example a webhook event or schedule) or when a user starts a run explicitly. + +Each task includes: + +* **Inputs**: a prompt, and often additional context from the triggering system (for example a Slack message, PR metadata, or CI logs). +* **Execution context (optional)**: an [Environment](/agent-platform/cloud-agents/environments/) that defines the repo, image, and startup commands the agent should run with. +* **Lifecycle state**: created → running → completed / failed. +* **Persistent record**: status, metadata, and a session transcript that can be reviewed after the task completes. + +:::note +If you are evaluating whether something should be a cloud agent, a good test is whether you can define:\ +(1) what triggers it, (2) what context it needs, and (3) how the team will inspect or validate the output. +::: + +### How cloud agents work + +Cloud agents run on the [Oz Platform](/agent-platform/cloud-agents/platform/), which provides the primitives for triggering work, orchestrating tasks, executing agents (optionally in environments), injecting secrets, and inspecting results. + +* Something **triggers** an agent task. +* The **orchestrator creates** and tracks the task. +* The agent **executes** on a host, optionally inside an [environment](/agent-platform/cloud-agents/environments/), with whatever [secrets](/agent-platform/cloud-agents/secrets/) and credentials it needs. + +The exact way tasks are triggered and executed depends on your deployment model (for example CLI-only, Warp-hosted orchestration, or self-hosted execution). Those options are covered in the [Deployment Patterns](/agent-platform/cloud-agents/deployment-patterns/) pages. + +For teams that need execution to stay within their network boundary, self-hosting supports two architectures: a **managed** worker daemon that lets Oz orchestrate agents in Docker containers on your machines, and an **unmanaged** mode where you run `oz agent run` directly in your CI, Kubernetes, or dev environment. See [Self-Hosting](/agent-platform/cloud-agents/self-hosting/) for details. + +### What you get by default + +Because cloud agents run on the [Oz Platform](/agent-platform/cloud-agents/platform/), each run is tracked and produces a persistent record that can be observed, shared, and audited (even if execution happens outside the Warp app). + +#### Codebase Context + +Cloud agent runs automatically benefit from [Codebase Context](/agent-platform/capabilities/codebase-context/) for semantic code understanding and search, as long as Codebase Context is enabled for your account. See [Codebase Context in cloud agent runs](/agent-platform/capabilities/codebase-context/#codebase-context-in-cloud-agent-runs) for details. + +#### Observability and steerability + +Cloud agent tasks are designed to be inspectable by the team: + +* [Agent Session Sharing](/agent-platform/local-agents/session-sharing/) lets authorized teammates attach to a running task to monitor progress and, where supported, steer the agent while it runs. +* Each run produces a session transcript and task metadata, which provides a record of what the agent did. +* A [management experience](/agent-platform/cloud-agents/managing-cloud-agents/) surfaces task status and history. + +#### Centralized configuration + +Cloud agent workflows often rely on shared configuration such as [MCP servers](/agent-platform/cloud-agents/mcp/), rules, saved prompts, environment variables, and [secrets](/agent-platform/cloud-agents/secrets/). + +Warp supports centralized configuration so the same workflow behaves consistently across triggers (for example Slack + CI + schedules), without duplicating setup in every system. + +For details on configuring MCP servers for cloud agents, see [MCP Servers](/agent-platform/cloud-agents/mcp/). + +#### API access to tasks + +The Oz Platform exposes task visibility via the [**Oz API and SDKs**](/reference/api-and-sdk/), so teams can: + +* Query which tasks are running or have run. +* Fetch task metadata and outcomes. +* Build internal dashboards or monitoring (for example success rates, runtime, failure reasons). + +### Using cloud agents with or without the Warp app + +Cloud agents do not require the Warp desktop app. Teams can deploy and operate them through the [Oz Platform](/agent-platform/cloud-agents/platform/) using: + +* [Oz CLI](/reference/cli/) — run agents from scripts, CI, or the terminal +* [Oz web app](/agent-platform/cloud-agents/oz-web-app/) — visual interface for managing runs, schedules, environments, and integrations (works on mobile) +* [Agent Session Sharing](/agent-platform/local-agents/session-sharing/) — attach to running tasks to monitor or steer +* [Agent Management UX](/agent-platform/cloud-agents/managing-cloud-agents/) — view agent activity and run history +* [APIs and SDKs](/reference/api-and-sdk/) — programmatic access for custom integrations + +If your team also uses Warp's terminal, you get an additional workflow: tasks launched via the CLI can be handed off into an interactive session for review, edits, or continuation. + +--- + +### Billing and plan requirements + +Cloud agents and [integrations](/agent-platform/cloud-agents/integrations/) run on the [Oz Platform](/agent-platform/cloud-agents/platform/) control plane, and usage is billed using credits. + +:::note +[Bring Your Own Key (BYOK)](/support-and-community/plans-and-billing/bring-your-own-api-key/) is not supported for cloud agent runs. BYOK keys are stored locally on your device and are not accessible to cloud-hosted agents. All cloud agent runs consume Warp credits. +::: + +#### For Cloud Agents via CLI/API + +Individual users can run cloud agents without being on a team. Requirements: + +* You need at least 20 credits (any type: normal Warp credits, [Cloud Agent Credits](/support-and-community/plans-and-billing/credits/#cloud-agent-credits), or Build plan credits) +* Cloud agents run on Warp-hosted infrastructure +* Self-hosted agents require a team subscription + +#### For Integrations (Slack/Linear) + +Integrations require you to be part of a [Warp team](/knowledge-and-collaboration/teams/) and additional requirements: + +* **Plan requirements** + * **Supported plans**: Build, Max, Business + * Not supported: Pro, Turbo, Lightspeed, legacy Business + * Your plan must support Add-on Credits. +* **Credit requirements** + * Your team must have at least 20 credits available (any type of Warp credits work) to run cloud agents and integrations. + * Usage is billed based on credit type and team configuration. + * Normal credits, [Cloud Agent Credits](/support-and-community/plans-and-billing/credits/#cloud-agent-credits), and [Add-on Credits](/support-and-community/plans-and-billing/add-on-credits/) all work. + +For more details, see [Access, Billing, and Identity Permissions](/agent-platform/cloud-agents/team-access-billing-and-identity/). + +:::caution +If your credit balance reaches zero, cloud agent runs will not be able to execute until credits are replenished. +::: + +--- + +### Learn more + +* [Cloud Agents Quick Start](/agent-platform/cloud-agents/quickstart/) — run your first cloud agent with an environment in ~10 minutes. +* [Oz Platform](/agent-platform/cloud-agents/platform/) — CLI, Oz API/SDK, orchestration, tasks, environments, hosts, integrations, and more. +* [Skills as Agents](/agent-platform/cloud-agents/skills-as-agents/) — run agents based on reusable skill definitions from the CLI, web app, API, or on a schedule. +* [Oz CLI](/reference/cli/) — shows how to run Oz agents in non-interactive mode from CI, scripts, or remote machines, including auth and common commands. +* [Environments](/agent-platform/cloud-agents/environments/) — explains how environments provide the runtime context (repo, image, startup commands) for agent tasks. +* [Oz API and SDK](/reference/api-and-sdk/) — documents the REST API for creating, querying, and monitoring agent tasks programmatically. +* [Agent Secrets](/agent-platform/cloud-agents/secrets/) — covers how to store, scope, and inject credentials into agent runs safely. +* [MCP Servers](/agent-platform/cloud-agents/mcp/) — how to configure MCP servers for agent tool access and how MCP configuration is applied across runs. +* [Deployment Patterns](/agent-platform/cloud-agents/deployment-patterns/) (beta) — compares common ways to deploy cloud agents and when to use each. +* [Access, Billing, and Identity Permissions](/agent-platform/cloud-agents/team-access-billing-and-identity/) — explains individual and team-level requirements, credit billing behavior, and the permission model for who can run, view, and steer cloud agent tasks. diff --git a/src/content/docs/agent-platform/cloud-agents/oz-web-app.mdx b/src/content/docs/agent-platform/cloud-agents/oz-web-app.mdx new file mode 100644 index 0000000..9579de0 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/oz-web-app.mdx @@ -0,0 +1,247 @@ +--- +title: Oz Web App +description: >- + Use the Oz web app to manage cloud agents, view runs, create schedules, and + configure environments and integrations from any browser or mobile device. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +The [Oz web app](https://oz.warp.dev) provides a visual interface for managing cloud agents. You can start runs, browse agents, create schedules, configure environments, and set up integrations—all without installing Warp or using the CLI. + +:::note +The Oz web app works on mobile devices, so you can monitor and manage your cloud agents from anywhere. +::: + +Watch this short demo to create an environment and run an agent using the Oz web app: +<VideoEmbed url="https://youtu.be/h9Wd77leIYg" /> + +## Quick reference + +<table><thead><tr><th width="150">Page</th><th width="120">Path</th><th>What you can do</th></tr></thead><tbody><tr><td><strong>Dashboard</strong></td><td><code>/dashboard</code></td><td>Quick actions, suggested agents, recent agents, and featured reads</td></tr><tr><td><strong>Runs</strong></td><td><code>/runs</code></td><td>View all runs, filter by status/source/creator, start new runs, inspect transcripts</td></tr><tr><td><strong>Agents</strong></td><td><code>/agents</code></td><td>Browse skills from your environments, view suggested skills, dispatch skills as agents</td></tr><tr><td><strong>Schedules</strong></td><td><code>/schedules</code></td><td>Create scheduled agents, pause/enable schedules, view run history</td></tr><tr><td><strong>Environments</strong></td><td><code>/environments</code></td><td>Create and manage environments with repos, Docker images, and setup commands</td></tr><tr><td><strong>Integrations</strong></td><td><code>/integrations</code></td><td>Connect Slack and Linear to trigger agents from external tools</td></tr></tbody></table> + +![The Oz Web App's management view.](../../../../assets/agent-platform/oz-web-app-runs-view.png) + +## When to use the web app + +The Oz web app is ideal when you want to: + +* **Monitor agent activity** — View runs, check status, and inspect outputs from any device +* **Start quick runs** — Dispatch agents without opening a terminal +* **Manage schedules visually** — Create and edit scheduled agents with a guided interface +* **Configure environments** — Set up repos, Docker images, and setup commands through a form-based flow +* **Set up integrations** — Connect Slack and Linear with a guided setup flow + +For scripting, automation, and CI/CD workflows, use the [Oz CLI](/reference/cli/) or [API](/reference/api-and-sdk/). + +--- + +## Getting started + +When you first sign in to the Oz web app, you'll see a guided onboarding flow that helps you get started based on your goals. + +The onboarding asks "What brings you to Oz?" and offers three paths: + +* **Create an agent automation** — Walks you through setting up a scheduled agent, integration-triggered agent, or other automation +* **Run Oz Cloud Agents in Warp** — Opens the Warp desktop app (or takes you to the download page) to run cloud agents interactively +* **Build an app that uses agents** — Links to the [Oz Platform](/agent-platform/cloud-agents/platform/) docs for using the CLI, SDK, or API + +You can skip onboarding at any time to go directly to the Runs page. + +--- + +## Dashboard + +The **Dashboard** page (`/dashboard`) is your starting point for common actions and discovery. It provides quick access to the features you use most. + +### Quick actions + +Four action cards at the top let you immediately: + +* **New run** — Start a cloud agent run +* **New agent** — Create a new skill +* **New schedule** — Set up a scheduled agent +* **New environment** — Configure a new execution environment + +Each action opens a guided side pane without leaving the Dashboard. + +### Suggested agents + +A curated list of pre-built skills from Warp's public [oz-skills repository](https://github.com/warpdotdev/oz-skills). Click **Run** on any suggested agent to start a run with that skill. + +### Recent agents + +Shows the last three agents you've run, so you can quickly re-run common workflows. If you haven't run any agents yet, you'll see prompts to start a new run or create your first agent. + +### Featured reads + +Links to curated articles and documentation to help you get the most out of Oz (visible on desktop). + +--- + +## Runs + +The **Runs** page (`/runs`) is your central view for monitoring cloud agent activity. It shows all runs across your account, including those triggered from the CLI, API, integrations, and schedules. + +### Run details + +Each run displays the following information: + +<table><thead><tr><th width="140">Field</th><th>Description</th></tr></thead><tbody><tr><td><strong>Status</strong></td><td>Working, succeeded, failed, canceled, errored, or blocked</td></tr><tr><td><strong>Title</strong></td><td>The run's title or prompt summary</td></tr><tr><td><strong>Environment</strong></td><td>Which environment the agent ran in</td></tr><tr><td><strong>Creator</strong></td><td>Who started the run</td></tr><tr><td><strong>Source</strong></td><td>Where the run was triggered from (CLI, API, Slack, Linear, scheduled)</td></tr><tr><td><strong>Artifacts</strong></td><td>Any outputs like PRs or files created</td></tr><tr><td><strong>Credits</strong></td><td>How many credits the run consumed</td></tr></tbody></table> + +Click any run to open the detail pane, where you can view the full transcript, artifacts, and metadata. + +### Filtering and search + +<table><thead><tr><th width="140">Quick filter</th><th>Shows</th></tr></thead><tbody><tr><td><strong>All</strong></td><td>All runs</td></tr><tr><td><strong>Mine</strong></td><td>Only runs you created</td></tr><tr><td><strong>Active</strong></td><td>Runs currently in progress</td></tr><tr><td><strong>Failed</strong></td><td>Runs that failed</td></tr><tr><td><strong>Recurring</strong></td><td>Runs triggered by schedules</td></tr></tbody></table> + +You can also search by title, prompt, or skill name, and add advanced filters for source, status, creator, and date range. + +--- + +### Starting a new run + +:::note +Click **New run** in the header to start a cloud agent. +::: + +1. **Select an agent (optional)** — Choose a skill to use as the base instructions, or select "Quick run" to run without a skill +2. **Select an environment** — Choose which environment the agent runs in +3. **Add a prompt** — Provide context and instructions for this specific run + +The skill provides base instructions; your prompt adds context for this particular execution. + +--- + +## Agents + +The **Agents** page (`/agents`) shows all skills available from your environments, plus suggested skills from Warp's public [oz-skills repository](https://github.com/warpdotdev/oz-skills). + +### Skill details + +Each skill displays: + +<table><thead><tr><th width="150">Field</th><th>Description</th></tr></thead><tbody><tr><td><strong>Name</strong></td><td>The skill's identifier</td></tr><tr><td><strong>Description</strong></td><td>What the skill does</td></tr><tr><td><strong>Environments</strong></td><td>Which environments have access to this skill</td></tr></tbody></table> + +![The Agents page in the Oz Web App.](../../../../assets/agent-platform/oz-web-app-agents.png) + +Filter by environment or switch to the **Suggested** tab to see pre-built skills for common workflows like code review, dependency updates, and documentation sync. + +### Running a skill as an agent + +Click any skill to view its details, then click **Run** to start an agent with that skill. You can also click **New run** from the header to start a run with optional skill selection. + +:::note +For more details on how skills work with cloud agents, see [Skills as Agents](/agent-platform/cloud-agents/skills-as-agents/). +::: + +### Creating new agents + +Click **New agent** to create a new skill. The guided flow helps you define the skill's instructions, which are then available for future runs. + +![Creating a new agent skill in the Oz Web App.](../../../../assets/agent-platform/oz-web-app-new-agent.png) + +--- + +## Schedules + +The **Schedules** page (`/schedules`) lets you create and manage scheduled agents that run automatically on a cron schedule. + +### Schedule details + +Each schedule displays: + +<table><thead><tr><th width="150">Field</th><th>Description</th></tr></thead><tbody><tr><td><strong>Name</strong></td><td>A descriptive name for the scheduled task</td></tr><tr><td><strong>Frequency</strong></td><td>Human-readable description of the cron schedule (e.g., "Every Monday at 10am")</td></tr><tr><td><strong>Next run</strong></td><td>When the schedule will next execute</td></tr><tr><td><strong>Environment</strong></td><td>Which environment the scheduled agent runs in</td></tr><tr><td><strong>Agent</strong></td><td>Which skill the schedule uses (if any)</td></tr><tr><td><strong>Status</strong></td><td>Whether the schedule is active or paused</td></tr></tbody></table> + +![The Schedules page in the Oz Web App.](../../../../assets/agent-platform/oz-web-app-schedules.png) + +--- + +### Creating a schedule + +:::note +Click **New schedule** in the header to create a scheduled agent. +::: + +1. **Name** — Give the schedule a descriptive name +2. **Frequency** — Set the cron schedule (with presets for common patterns) +3. **Environment** — Select the environment to run in +4. **Agent (optional)** — Choose a skill to use +5. **Prompt** — Define what the agent should do each time it runs + +--- + +### Managing schedules + +Click any schedule to view its details and recent run history. From the detail pane, you can: + +* **Edit** the schedule configuration +* **Pause** or **enable** the schedule +* **Delete** the schedule +* **View past runs** triggered by this schedule + +:::note +For CLI-based schedule management, see [Scheduled Agents](/agent-platform/cloud-agents/triggers/scheduled-agents/). +::: + +--- + +## Environments + +The **Environments** page (`/environments`) shows all environments configured for your account. Environments define the execution context for cloud agents, including repos, Docker images, and setup commands. + +### Environment details + +Each environment displays: + +<table><thead><tr><th width="170">Field</th><th>Description</th></tr></thead><tbody><tr><td><strong>Name</strong></td><td>The environment's identifier</td></tr><tr><td><strong>Docker image</strong></td><td>The container image used for execution</td></tr><tr><td><strong>Repositories</strong></td><td>Which repos the agent can access</td></tr><tr><td><strong>Setup commands</strong></td><td>Commands run before the agent starts</td></tr></tbody></table> + +![The Environments page in the Oz Web App.](../../../../assets/agent-platform/oz-web-app-environments.png) + +--- + +### Creating an environment + +:::note +Click **New environment** in the header to create a new environment. +::: + +1. **Name** — Give the environment a descriptive name +2. **Docker image** — Specify a Docker image (Warp provides prebuilt dev images, or use your own) +3. **Repositories** — Add GitHub repos the agent should have access to +4. **Setup commands** — Define commands to run when the environment starts (e.g., `npm install`) + +:::note +For advanced environment configuration, see [Environments](/agent-platform/cloud-agents/environments/) and the [CLI reference](/reference/cli/integration-setup/). +::: + +--- + +## Integrations + +The **Integrations** page (`/integrations`) lets you configure first-party integrations with Slack and Linear. + +### Available integrations + +<table><thead><tr><th width="120">Integration</th><th>Description</th></tr></thead><tbody><tr><td><strong>Slack</strong></td><td>Tag @Oz in messages or threads to trigger agents directly from Slack conversations</td></tr><tr><td><strong>Linear</strong></td><td>Tag @Oz on issues to trigger agents from your issue tracker</td></tr></tbody></table> + +![The Integrations page in the Oz Web App.](../../../../assets/agent-platform/oz-web-app-integrations.png) + +### Setting up an integration + +Click an integration to start the guided setup flow. You'll authorize Warp to connect with the external service, select an environment, and configure any integration-specific settings. + +:::note +For detailed integration setup instructions, see [Slack](/agent-platform/cloud-agents/integrations/slack/) and [Linear](/agent-platform/cloud-agents/integrations/linear/). +::: + +--- + +## Related resources + +* [Cloud Agents Overview](/agent-platform/cloud-agents/overview/) — Learn about cloud agents and when to use them +* [Skills as Agents](/agent-platform/cloud-agents/skills-as-agents/) — Run agents based on reusable skill definitions +* [Scheduled Agents](/agent-platform/cloud-agents/triggers/scheduled-agents/) — Run agents automatically on a cron schedule +* [Environments](/agent-platform/cloud-agents/environments/) — Configure runtime context for cloud agents +* [Managing Cloud Agents](/agent-platform/cloud-agents/managing-cloud-agents/) — Monitor agent activity and inspect runs +* [Oz CLI](/reference/cli/) — Command-line interface for running agents +* [Oz API & SDK](/reference/api-and-sdk/) — Programmatic access to cloud agents diff --git a/src/content/docs/agent-platform/cloud-agents/platform.mdx b/src/content/docs/agent-platform/cloud-agents/platform.mdx new file mode 100644 index 0000000..9e1dd88 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/platform.mdx @@ -0,0 +1,295 @@ +--- +title: Oz Platform +description: >- + The Oz Platform provides the CLI, API/SDK, orchestration, environments, and + observability for cloud agents. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Cloud agents run on the **Oz Platform**. The platform gives you a consistent way to **trigger work**, **orchestrate and track tasks**, **execute agents** (in an optional [environment](/reference/cli/integration-setup/), on a host), and inspect outcomes with team visibility. First-party [integrations](/agent-platform/cloud-agents/integrations/) connect external events — like Slack messages, GitHub PRs, or CI failures — to cloud agents automatically. + +<VideoEmbed url="https://youtu.be/poLkJhO7fdo" /> + +:::note +**New to cloud agents?** Start with the [Cloud Agents Quick Start](/agent-platform/cloud-agents/quickstart/) to run your first agent in ~10 minutes. +::: + +**Most production setups follow the same flow:** + +1. A **trigger** fires (schedule, integration event, CI step, webhook, API call, or manual run). +2. Warp's **orchestration layer** creates a cloud agent task and tracks its lifecycle. +3. The agent executes on a **host**, optionally inside an environment, using the required configuration and credentials. +4. The task produces a **persistent record** (status, metadata, transcript, outputs) your team can review and manage. + +![Oz Platform architecture showing Trigger, Agent, Environment, and Artifacts components](../../../../assets/agent-platform/most-flexible-platform-for-building-with-agents.png) + +![Oz Platform detailed architecture showing components, triggers, orchestrator, and agent runners](../../../../assets/agent-platform/oz-diagram.png) + +The sections below describe the Oz Platform primitives that power this flow, and how they compose. + +--- + +### Key concepts + +Before diving into the components, it helps to align on a few terms: + +* **Trigger**: The event that starts work (for example: cron, Slack mention, PR opened, CI failure, “run now”). +* **Task:** The unit of work Warp tracks. A task includes inputs, state, metadata, and an execution record (where it ran, what it did, and what it produced). +* **Context**: Additional inputs attached to a task (for example: a Slack message, PR metadata, CI logs, repository diffs). +* **Outputs:** What the task produced (for example: created a PR, posted a Slack reply, emitted a report, or just a transcript + summary). + +In practice: **triggers create tasks; tasks execute on a host (optionally in an environment); tasks produce outputs.** + +--- + +### Oz CLI + +The [Oz CLI](/reference/cli/) is the **headless interface** for running Oz agents in non-interactive mode. It's commonly used in CI, scripts, and server environments where there is no interactive UI. For interactive workflows, use the [agent](/agent-platform/local-agents/overview/) embedded in Warp's desktop app. + +A key property of the CLI is that it is **cloud-connected**. Even when an agent is started on a local machine or in CI, it reports progress to Warp’s servers. This enables team visibility, session sharing (where supported), and programmatic tracking through the API. + +#### When to use the CLI + +Use the CLI when: + +* You want to run an agent anywhere (local machine, CI runner, remote dev box, server). +* An external system is orchestrating runs (for example GitHub Actions, custom automation, incident tooling). +* You want task observability and auditing without requiring Warp desktop. + +#### How it fits in the Oz Platform + +Depending on the command, the CLI typically: + +* Authenticates as you (or as a member of your team, if applicable). +* Starts work by creating a task in the orchestrator (either directly via CLI commands, or indirectly via an integration/schedule). +* Streams progress back to Warp for live observability and a persistent record. +* Optionally attaches an environment and other configuration. + +#### Example (no environment) + +You can also run an agent locally without an environment using a command like: + +```bash +oz agent run ... +``` + +--- + +### Warp Orchestrator + +The orchestration layer manages the lifecycle of cloud agent tasks. It creates tasks, tracks state transitions, and is the system of record for what’s running and what ran. + +#### What the orchestrator does + +The orchestrator: + +* Runs on Warp's servers (cloud control plane). +* Creates tasks when triggers fire (integrations, schedules, API calls, or explicit starts). +* Tracks lifecycle state (created → running → completed/failed) and associated metadata. +* Exposes task lifecycle operations via the [Oz CLI](/reference/cli/) and a [REST API](/reference/api-and-sdk/) (create tasks, query history, and inspect status/outputs). +* Powers SDKs (TypeScript/Python) for programmatic usage on top of the orchestrator API. + +#### When teams use the API/SDK + +Teams typically use the API/SDK when: + +* Triggering agents from custom internal systems (incident tools, bots, internal automation). +* Building internal dashboards or monitoring (success rates, runtime, failure reasons). +* Coordinating many runs (fanout, sharding, queueing, retries, rate limiting at the app layer). +* Creating higher-level workflows that treat tasks as building blocks. + +--- + +### Environments + +[Environments](/agent-platform/cloud-agents/environments/) define the execution context an agent should run in. + +**An Environment typically includes:** + +* A Docker image (toolchain and runtime). +* One or more repositories (or a workspace definition). +* Startup commands and configuration (setup steps, dependency install, bootstrapping). +* Optional environment variables and other runtime settings. + +:::note +Environments are how teams make agent runs consistent across triggers (Slack, CI, schedules) and across hosts. +::: + +#### Environments are optional + +Agents can run without an environment (for example, against an existing local checkout or a CI workspace). Teams usually move to environments when they want stronger reproducibility, isolation, and standardization. + +#### When to use environments + +Environments are recommended when: + +* The agent needs a consistent toolchain (linters, build tools, language runtimes). +* You want repeatable execution across CI and cloud execution. +* You want standard execution across a team (same repo state rules, same setup steps). +* You want to reduce “works on my machine” variability across tasks. + +--- + +### Oz API and SDK + +The Oz [Agent API](/reference/api-and-sdk/) is the HTTP interface to the Oz Platform. It lets you create and inspect cloud agent tasks from any system (CI, cron, backend services, internal tools), without requiring the Warp desktop app. + +**What you can do with the API** + +* Run an agent by submitting a prompt plus optional configuration (model, environment, MCP servers, base prompt, etc.). +* Monitor execution by listing tasks and tracking state transitions over time (for example: `QUEUED` → `INPROGRESS` → `SUCCEEDED/FAILED`). +* Inspect results and provenance by fetching a task’s full details, including the original prompt, creator/source metadata, session link, and resolved agent configuration. + +**Oz Agent SDKs** + +Oz provides official [Python](https://github.com/warpdotdev/oz-sdk-python) and [TypeScript SDKs](https://github.com/warpdotdev/oz-sdk-typescript) that wrap the Oz API with: + +* Typed requests/responses (autocomplete, fewer schema mistakes) +* Built-in retries and timeouts (with per-request overrides) +* Consistent error types mapped to API status codes +* Helpers for raw responses when you need headers/status/custom parsing + +If you’re building an integration (CI, Slack bots, internal tooling, orchestrators), the [SDKs](/reference/api-and-sdk/) are typically the quickest and safest starting point. + +**SDK vs raw REST** + +* Use the SDK when you want strong typing, standardized error handling, and easy concurrency patterns. +* Use raw REST when you want minimal dependencies or full control over your HTTP client. + +:::note +For full endpoint semantics and schema definitions, please refer to the dedicated [API docs](/reference/api-and-sdk/) and Models/Schema reference, plus the [Python SDK](https://github.com/warpdotdev/oz-sdk-python) and [TypeScript SDK](https://github.com/warpdotdev/oz-sdk-typescript) repos for the latest usage/examples. +::: + +--- + +### Execution hosts + +A host describes where the agent actually executes. Warp supports multiple execution models depending on your security, compliance, and operational requirements. + +#### Warp-hosted execution + +With Warp hosting: + +* Warp runs the environment on Warp-managed infrastructure. +* This is the default model for teams that want the simplest setup and do not need execution to occur inside their network boundary. + +#### Self-hosted execution + +With self-hosting: + +* The agent runs on customer-managed infrastructure. +* Oz orchestrator still manages lifecycle and observability. +* This is used when teams want code and execution to remain on their own systems rather than being cloned or executed in Warp's cloud. + +:::note +**Enterprise feature**: Self-hosted execution requires an Enterprise plan. See [Self-Hosting](/agent-platform/cloud-agents/self-hosting/) for setup instructions. +::: + +--- + +### Integrations + +[Integrations](/agent-platform/cloud-agents/integrations/) connect external events to cloud agent tasks. When an event occurs in a third-party system, Warp creates a task with the relevant context and starts it automatically. + +Warp supports two integration models: + +* **First-party integrations** — Warp manages the event subscription and context extraction end to end. +* **Custom integrations** — you handle event ingestion and filtering, then call the API or SDK to create tasks. + +#### First-party integrations + +First-party integrations can be configured with a simple setup flow (for example via CLI): + +```bash +oz integration create … +``` + +Warp registers webhooks with the third-party system, receives events, extracts context (payload, metadata, links, logs), and creates a task — optionally in an [Environment](/agent-platform/cloud-agents/environments/). + +Examples of context extracted by first-party integrations: + +* [Slack](/agent-platform/cloud-agents/integrations/slack/): message text, channel, thread, and user identity +* [GitHub](/agent-platform/cloud-agents/integrations/github-actions/): PR metadata, diffs, labels, and check results +* CI: logs, job metadata, and artifacts + +#### Custom integrations + +With custom integrations, you own the webhook and event-handling logic. Your system receives an event, applies any filtering or enrichment you need, and then calls the Oz API (directly or via an SDK) to create a task. The resulting task is still a full Oz agent run — observable, manageable, and auditable like any other. + +Custom integrations are a good fit when: + +* You have internal event sources (custom tooling, proprietary systems). +* You need custom filtering, routing, or enrichment before triggering an agent. +* You want to implement your own permissioning, queueing, or governance around triggers. + +--- + +### Secrets + +Cloud agents often need credentials to access external systems (APIs, cloud providers, databases, internal tools, MCP servers). Warp provides a [secrets store](/agent-platform/cloud-agents/secrets/) that can inject secrets at runtime so agents can use authenticated tools without exposing secret values in logs or UI. + +#### What secrets are for + +In most deployments, secrets power: + +* API keys and tokens (GitHub, Slack, Linear, internal APIs). +* Shared team credentials (cloud providers, CI identities). +* Database credentials (read-only query bots, reporting). +* Credentials required by MCP servers (static tokens/keys). + +#### Scoping and control + +Today, secrets support two scopes: + +* **Team secrets:** shared credentials available to the team (useful for shared infrastructure). +* **Personal secrets**: credentials tied to an individual (useful when actions must be attributable to a specific person). + +--- + +### Management and observability + +Cloud agents are designed so task execution is visible to the team. + +While a task is executing, the agent reports progress and status back to Warp. After completion, the task retains a persistent record for review and debugging. + +Warp provides multiple surfaces for observability: + +* [Management UI](/agent-platform/cloud-agents/managing-cloud-agents/): lists tasks, status, timing, metadata, and history. +* [Agent Session Sharing](/agent-platform/local-agents/session-sharing/): authorized teammates can attach to a running task to monitor and, where supported, steer it. +* [APIs](/reference/api-and-sdk/) and SDKs: query task history, build monitoring, and generate reports. + +#### Access control + +**Access control is part of the model:** + +* Teams can restrict who can run, view, or intervene in agent tasks. +* At the same time, organizations can enable system-wide visibility where appropriate for auditing and operations. + +### Centralized configuration + +Cloud agent setups often include shared configuration such as: + +* [MCP Servers](/agent-platform/cloud-agents/mcp/) +* [rules / guardrails](/agent-platform/capabilities/rules/) +* [saved prompts](/knowledge-and-collaboration/warp-drive/prompts/) +* [environment variables](/knowledge-and-collaboration/warp-drive/environment-variables/) +* [secrets](/agent-platform/cloud-agents/secrets/) + +Warp supports centralized configuration so these settings apply consistently regardless of where a task is launched. + +This is especially useful when the same workflow can be triggered from multiple places (for example Slack, CI, and schedules). Instead of duplicating setup across systems, teams can keep configuration in one place and reuse it across triggers. + +### Using the Oz Platform with or without the Warp app + +[Cloud agents](/agent-platform/cloud-agents/overview/) do not require Warp's desktop terminal. Teams can operate cloud agent workflows using: + +* [Oz CLI](/reference/cli/) — run agents from scripts, CI, or the terminal +* [Oz web app](/agent-platform/cloud-agents/oz-web-app/) — visual interface at [oz.warp.dev](https://oz.warp.dev) for managing runs, schedules, environments, and integrations (works on mobile) +* [Session sharing](/agent-platform/local-agents/session-sharing/) — attach to running tasks to monitor or steer +* [Management UI](/agent-platform/cloud-agents/managing-cloud-agents/) — view agent activity and run history +* [APIs and SDKs](/reference/api-and-sdk/) — programmatic access for custom integrations + +**If your team also uses Warp’s terminal, you gain an additional workflow:** + +* Tasks launched via the CLI can be handed off into an interactive session for review, edits, or continuation. +* This is useful when you want a human checkpoint (final edits, validation, merge decisions) without losing the audit trail from the cloud agent run. diff --git a/src/content/docs/agent-platform/cloud-agents/quickstart.mdx b/src/content/docs/agent-platform/cloud-agents/quickstart.mdx new file mode 100644 index 0000000..e2e3ce9 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/quickstart.mdx @@ -0,0 +1,174 @@ +--- +title: Cloud Agents Quick Start +description: >- + Learn how to run your first Oz cloud agent in ~10 minutes. Cloud agents run + in remote environments, enabling automation, scheduling, and team + collaboration. +--- + +**Oz cloud agents** run in a remote environment and can be triggered from events, schedules, integrations, or manually. This enables scaling agents off your laptop, automating development tasks, and building apps on top of agents. Oz handles the orchestration, execution, and observability. + +Cloud agents can run interactively (where you steer them in real-time) or autonomously (as background tasks). Each run creates a persistent session that your team can inspect, share, and query through the Warp app, the CLI, web app, or API. + +This guide walks you through running your first cloud agent with an environment in about 10 minutes. You'll create an environment, if needed, and launch a cloud agent to help with a development task. + +**Common use cases for cloud agents:** + +* Launch parallel cloud coding agents to multithread complex development tasks +* Automate repetitive development tasks (e.g., feature-flag cleanup, documentation updates, fixing server crashes) +* Build apps on top of agents, like bug triage and incident response systems + +--- + +## Prerequisites + +Before you begin, make sure you have: + +* **Warp desktop app** - Download from [warp.dev](https://warp.dev) +* **Warp account** - Create an account at [oz.warp.dev](https://oz.warp.dev) + +:::note +New to Warp? You'll get credits to try cloud agents. You need at least 20 credits available to run cloud agents and integrations. +::: + +--- + +## Running your first Oz cloud agent + +_~10 minutes • Recommended for all users_ + +### 1. Open Warp + +If you don't have Warp yet, download it from [warp.dev](https://warp.dev) and sign in to your account. When you open the Warp desktop app, you're automatically authenticated to Warp's services. + +### 2. Run the `/cloud-agent` command + +In Warp's terminal input, type: + +```bash +/cloud-agent +``` + +This launches a new cloud agent for you. + +**How this works:** The `/cloud-agent` command is your entry point to cloud agents. It checks if you have an environment set up, and if not, it guides you through creating one. + +### 3. Create your environment + +:::note +**Already have an environment?** The `/cloud-agent` command will use your existing one. To create additional environments for different projects, use `/create-environment`. +::: + +If you don't have an environment yet, the `/cloud-agent` setup flow will guide you through creating one. You will need: + +* **Name**: A label to identify this environment (required) +* **Repo(s)**: Type repo in `owner/repo` format or select from the dropdown. Click **Auth with GitHub** if you need to connect your repos. +* **Docker image**: Your runtime environment (e.g., `python:3.11`, `node:20`). Not sure? Click **Suggest image** and Warp will recommend one based on your repos. +* **Setup command(s)**: Commands to prepare your workspace, like `pip install -r requirements.txt` or `npm ci`. Add each command separately by pressing Enter. +* **Description**: Optional notes about what this environment is for. + +**How this works:** Environments are composed of Docker containers + Git repos + startup commands. They give your cloud agent a consistent workspace with your code and tools. Warp detects your project automatically and suggests the right setup. Environments can be shared with your team so everyone uses the same configuration. + +### 4. Describe what you want the agent to do + +Enter your prompt (e.g., "analyze test coverage and suggest improvements"). The agent executes in the cloud with full access to your environment. + +You can continue conversing with the agent in real-time, watch its progress, and provide additional guidance as it works autonomously on your task. + +**How this works:** Your cloud agent is now running in Warp's infrastructure (not on your machine). It clones your repos, runs your setup commands, and starts working on your prompt. The agent has full access to your code and can run tests, make changes, and create artifacts like PRs. + +### 5. View run details + +You can view details of your agent's run, including commands executed, files changed, and environment used, several different ways: +* In the Warp app, open the [conversations panel](/agent-platform/local-agents/interacting-with-agents/#conversation-panel) to see all your agent runs. +* Click the session link in your terminal output. +* Go to [oz.warp.dev](https://oz.warp.dev) and navigate to the `Runs` tab. +* Access from mobile via the [Oz web app](/agent-platform/cloud-agents/oz-web-app/). + +**Breaking it down:** Every cloud agent run is auto-tracked. You get a shareable link, a run record, and full visibility into what the agent did. You or your teammates can watch the agent's progress in real-time and even steer it if needed. The run record persists after completion so you can review it later. + +### 6. Make it reusable with a skill (optional) + +Turn your successful run into a skill that you can reuse: + +```bash +/create-skill +``` + +Follow the prompts to save your task definition. Once created, you can run it again, schedule it, trigger it from Slack/Linear, or share it with your team. + +**How this works:** Skills capture successful agent workflows as reusable building blocks. Instead of typing the same prompt repeatedly, you define it once. You can use it yourself, share it with teammates, schedule it to run automatically, or trigger it from integrations. Learn more about [Skills as Agents](/agent-platform/cloud-agents/skills-as-agents/). + +**Prefer using the CLI?** See the [Oz CLI Quick Start](/reference/cli/quickstart/) for CLI-based workflows. + +--- + +## Next steps + +{/* TODO: When advanced guides exist, refactor this section to link to them instead of providing instructions here. + Goal: Create a chain of "next steps" throughout docs that users can "fall into" and keep learning. + Each next step should link to a dedicated guide where they can learn more, rather than explaining everything here. + Example structure: + - "Schedule agents for recurring tasks" -> link to scheduling guide + - "Connect integrations" -> link to integrations guide + - "Build with the API" -> link to API guide + This creates a learning path rather than a single long quickstart. */} + +Now that you've run your first cloud agent, here are some next steps: + +### Automate recurring tasks + +[Schedule agents](/agent-platform/cloud-agents/triggers/scheduled-agents/) to run on cron schedules for maintenance tasks like weekly dependency checks or daily dead code cleanup. + +```bash +oz schedule create \ + --name "weekly-dependency-check" \ + --cron "0 10 * * 1" \ + --environment <ENV_ID> \ + --prompt "check for dependency updates and open PR" +``` + +### Trigger agents from integrations + +**Slack integration** - Tag @Oz in any Slack channel to get immediate help with code reviews, debugging, or incident response. Your team can discuss problems in Slack while Oz analyzes code, opens PRs, or investigates issues in the background. Results post directly back to the thread. [Learn more](/agent-platform/cloud-agents/integrations/slack/) + +**Linear integration** - Connect Oz to Linear to automate bug triage and fixes. Tag @Oz on an issue to reproduce the bug, identify root causes, and open a PR with a fix—closing the loop from bug report to resolution without leaving Linear. [Learn more](/agent-platform/cloud-agents/integrations/linear/) + +**GitHub Actions** - Run agents in CI/CD pipelines to automate tasks like generating release notes, running security audits, or validating migrations. Trigger agents on PRs, commits, or releases to keep workflows moving without manual intervention. [Learn more](/agent-platform/cloud-agents/integrations/github-actions/) + +:::note +Integrations require a team on Build, Max, or Business plan. +::: + +### Build automations and apps on top of Oz agents + +Use the [Oz API & SDK](/reference/api-and-sdk/) to trigger agents programmatically from your own systems and workflows. + +--- + +## Troubleshooting + +**Environment creation fails**\ +Use official Docker Hub images like `node`, `python`, or `rust` for best compatibility. Ensure your GitHub repos are accessible. If using a custom image, avoid Alpine/musl-based images—the agent runtime requires glibc. See [Environments](/agent-platform/cloud-agents/environments/) for more guidance on choosing Docker images. + +**Agent can't access repos**\ +Warp prompts you to authorize GitHub when you create an environment or trigger your first agent. If authorization fails or needs updating, see [How GitHub Authorization works](/reference/cli/integration-setup/#how-github-authorization-works). For automated workflows using team API keys, make sure [team GitHub authorization](/agent-platform/cloud-agents/team-access-billing-and-identity/#team-github-authorization) is configured in the Admin Panel. Also verify that repos are correctly configured in your environment with `oz environment get <ENV_ID>`. + +**Not enough credits to run cloud agents**\ +Your team needs at least 20 credits available (any type of Warp credits work). Check your credit balance in Settings or see [Access, Billing, and Identity](/agent-platform/cloud-agents/team-access-billing-and-identity/) for details on credit requirements and which plans support cloud agents. + +**More resources** + +* [Environments deep dive](/agent-platform/cloud-agents/environments/) +* [Cloud Agents FAQs](/agent-platform/cloud-agents/faqs/) +* [Managing Cloud Agents](/agent-platform/cloud-agents/managing-cloud-agents/) + +--- + +## What to explore next + +Now that you've run your first cloud agent, automate recurring work or connect agents to your team's tools. + +* **[Scheduled Agents quickstart](/agent-platform/cloud-agents/triggers/scheduled-agents-quickstart/)** - Set up an agent to run on a cron schedule for recurring tasks like weekly dependency checks. +* **[Integrations quickstart](/agent-platform/cloud-agents/integrations/quickstart/)** - Connect Oz to Slack and Linear so your team can trigger agents from mentions and issues. +* **[Skills](/agent-platform/capabilities/skills/)** - Turn successful agent workflows into reusable instructions you can schedule, trigger, or share. diff --git a/src/content/docs/agent-platform/cloud-agents/secrets.mdx b/src/content/docs/agent-platform/cloud-agents/secrets.mdx new file mode 100644 index 0000000..6013224 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/secrets.mdx @@ -0,0 +1,241 @@ +--- +title: Secrets +description: >- + Securely store, scope, and inject credentials for Warp cloud agents across + CLI, Slack, Linear, and scheduled runs—without ever exposing secret values. +--- + +Cloud agents often need to interact with external systems such as APIs, databases, cloud providers, or internal tooling. To do this safely, Warp provides Warp-managed **agent secrets**, a secure way to store, scope, and inject credentials into cloud agent runs without exposing secret values to users or logs. + +Warp-managed secrets are designed to work across [cloud agent](/agent-platform/cloud-agents/overview/) and [integration](/agent-platform/cloud-agents/integrations/) triggers (CLI, Slack, Linear, and schedules), support both team-wide and personal credentials, and give engineering and security teams visibility into what agents can access. + +**Warp-managed secrets are useful when:** + +* An cloud agent needs to call an API or CLI that does not support OAuth +* You are using [MCP servers](/agent-platform/cloud-agents/mcp/) that expect static tokens or keys +* An agent needs credentials for tools like cloud CLIs, databases, monitoring systems, or internal services +* You want centralized auditing and control over what credentials agents can access + +### Common use cases + +* Run SQL queries against BigQuery or Metabase to answer questions like “what changed in last night’s pipeline run” or “how many users hit this error today,” using a read-only service account or API token. +* Call cloud or infrastructure CLIs to take small, predefined remediation steps when an alert fires, such as restarting a service, scaling a deployment, or clearing a stuck job, using tightly scoped credentials. +* List and review all API keys, service accounts, and tokens that cloud agents can access to verify scopes, rotation policies, and ownership match internal security requirements. + +--- + +### How Warp-managed secrets work + +Warp provides a set of CLI commands for creating, updating, and listing secrets. Secret values are stored securely and cannot be retrieved once created. + +At runtime, **Warp sets the relevant secrets as environment variables** for each cloud agent run, based on who triggered the agent and how it was triggered. + +:::note +Secret values are available only to the agent process (and any subprocesses it spawns) during execution, and **can’t be viewed or retrieved afterward.** +::: + +Key properties of secrets: + +* **Scoped** to either a team or an individual user +* Secret values are **never readable after creation** (only metadata is visible) +* **Automatically set** for cloud agent runs when in scope + +### Secret scopes + +Each secret has a scope that determines who can use it. + +#### Team secrets + +Team secrets are shared across the entire team and are available to all cloud agents running on behalf of the team. + +**Key characteristics:** + +* Always injected into cloud agent runs, regardless of how the agent is triggered (CLI, Slack, Linear, or scheduled runs) +* Available to agents running with or without a specific user context +* Ideal for shared infrastructure credentials, service accounts, and read-only API keys + +:::note +Because team secrets are broadly available and may be used by fully automated or scheduled agents, they should generally be created **using bot or service accounts**, rather than credentials tied to an individual person. +::: + +**For example:** + +* Use a Metabase service account or read-only API token, not a personal Metabase API key +* Use cloud provider service accounts with minimal required permissions +* Use integration-specific tokens created for automation + +This ensures credentials remain valid as team membership changes, permissions are tightly scoped, and ownership and rotation align with internal security policies. + +#### Personal secrets + +Personal secrets belong to an **individual user**. + +* Only available to cloud agents triggered by that user +* Not accessible to teammates or user-less triggers +* Useful for personal API keys or credentials tied to an individual account + +--- + +## Managing agent secrets with the Oz CLI + +Secrets are managed using the oz secret command family. + +You can create secrets interactively or from a file. + +**Create a team secret interactively** + +```bash +oz secret create --team METABASE_API_KEY +``` + +You will be prompted to enter the value securely in the terminal. + +**Create a personal secret from a file** + +```bash +oz secret create --personal --value-file api_key.txt METABASE_API_KEY +``` + +This is useful for long values such as JSON blobs or private keys. + +#### Adding descriptions + +Descriptions help with auditing and rotation tracking. + +```bash +oz secret create --team \ + --description "Rotate every 2 weeks; owned by platform team" \ + MY_SECRET +``` + +Descriptions are visible in listings but never expose the secret value. + +#### Updating a secret + +Updating a secret replaces its value and/or description while keeping the same name and scope. + +**Update a secret value interactively** + +```bash +oz secret update --team --value METABASE_API_KEY +``` + +You will be prompted to enter the new value securely in the terminal. + +**Update a secret value from a file** + +```bash +oz secret update --team \ + --value-file new_api_key.txt \ + METABASE_API_KEY +``` + +This is the recommended way to rotate credentials. + +**Update a secret's description (`-d`)** + +```bash +oz secret update --team \ + --description "Rotated 2026-02-26; owned by platform team" \ + METABASE_API_KEY +``` + +#### Deleting a secret + +To permanently remove a secret, use `oz secret delete`: + +```bash +oz secret delete --team METABASE_API_KEY +``` + +You will be prompted for confirmation before the secret is deleted. Add `--force` to skip the confirmation prompt. Replace `--team` with `--personal` to delete a personal secret. + +```bash +oz secret delete --team --force METABASE_API_KEY +``` + +:::caution +Deleting a secret is permanent. Any cloud agent runs that depend on the deleted secret will no longer receive it as an environment variable. +::: + +#### Listing secrets + +You can list all secrets you have access to. + +```bash +oz secret list +``` + +Example output: + +```bash +NAME SCOPE LAST UPDATED +METABASE_API_KEY team 1 week ago +GCP_SERVICE_ACCOUNT_JSON team yesterday +MY_MCP_SERVER_TOKEN personal 10:00am +``` + +**Secret values are never displayed.** + +### How secrets are made available to cloud agents + +When an cloud agent starts, Warp determines which secrets are in scope and sets them as environment variables in the agent’s execution environment. + +Today, secrets are provided as environment variables using the secret name as the variable name. For example: + +```bash +METABASE_API_KEY=******** +``` + +--- + +### Secret availability by trigger type + +Which secrets an agent receives depends on how the agent was triggered. + +#### User-initiated triggers + +When an agent is triggered by a specific user, such as: + +* Oz CLI +* Slack mentions +* Linear updates + +**The agent receives:** + +* All team-level secrets +* The triggering user’s personal secrets + +It **does not receive personal secrets** belonging to other team members. + +When an agent is triggered without a user context, such as: + +* [Scheduled (cron) agents](/agent-platform/cloud-agents/triggers/scheduled-agents/) +* Fully automated [integrations](/agent-platform/cloud-agents/integrations/) + +The agent receives: + +* Team-level secrets only + +:::caution +Personal secrets are never injected in these cases. +::: + +--- + +### Auditing and security considerations + +Warp is designed to make secret usage auditable and predictable: + +* Secret values cannot be read or exported after creation +* All secrets are explicitly scoped to a team or user +* Engineering and security leads can list all secrets available to them +* Rotation is handled by updating secrets in place +* Cloud agents only receive secrets that are in scope for the trigger + +**Teams remain responsible for:** + +* Choosing appropriate scopes for each secret +* Limiting permissions on external systems (for example, read-only API keys) +* Rotating credentials according to internal policies +* Managing which agents and triggers exist within their environment diff --git a/src/content/docs/agent-platform/cloud-agents/self-hosting/index.mdx b/src/content/docs/agent-platform/cloud-agents/self-hosting/index.mdx new file mode 100644 index 0000000..21bdeae --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/self-hosting/index.mdx @@ -0,0 +1,218 @@ +--- +title: Self-hosting +description: >- + Run Oz cloud agents on your own infrastructure. Choose between a managed + worker daemon orchestrated by Oz or unmanaged CLI-based execution you + control. +--- + +Self-hosting lets your team run Oz cloud agent workloads on your own infrastructure instead of Warp-managed servers. You control the execution environment, compute resources, and network access. Repositories are cloned and stored only on your machines, and agents can reach services behind your VPN or firewall. + +**New to self-hosting?** Start with the [Self-hosting quickstart](/agent-platform/cloud-agents/self-hosting/quickstart/) to get a managed worker running on Docker in under 10 minutes. + +**Want a CLI-only path with no Docker requirement?** Jump straight to the [Unmanaged quickstart](/agent-platform/cloud-agents/self-hosting/unmanaged/#unmanaged-quickstart) to run `oz agent run` directly on any host. + +:::note +**Enterprise feature**: Self-hosted Oz agents are available exclusively to teams on an Enterprise plan. To enable self-hosting for your team, [contact sales](https://warp.dev/contact-sales). +::: + +## Managed vs unmanaged + +Self-hosting has two architectures. The core distinction is **who orchestrates agent runs** — not who owns the compute. Both models keep code and execution on your infrastructure. + +* **Managed** — Oz orchestrates agent runs. You run the `oz-agent-worker` daemon on your infrastructure; it connects to Oz and waits for work. Slack mentions, Linear comments, schedules, API calls, and `oz agent run-cloud` commands all route tasks to your worker, which executes them in isolated Docker containers, Kubernetes Jobs, or directly on the host. Similar to a [GitHub self-hosted runner](https://docs.github.com/en/actions/hosting-your-own-runners). +* **Unmanaged** — You orchestrate agent runs. You invoke `oz agent run` directly from your existing CI pipeline, Kubernetes pod, VM, or dev box. Oz provides session tracking and observability for each run, but does not start or stop agents for you. + +### At a glance + +| Aspect | **Managed** | **Unmanaged** | +| --- | --- | --- | +| **Who triggers runs** | Oz (Slack, Linear, schedules, API, `run-cloud`) | Your system (CI, cron, scripts) | +| **What runs on your infra** | Long-lived `oz-agent-worker` daemon | One-shot `oz agent run` invocations | +| **OS support** | Linux (macOS/Windows coming) | Linux, macOS, Windows | +| **Execution isolation** | Docker container, Kubernetes Job, or direct host | Whatever your host provides | +| **Automatic environment setup** | Yes (via Warp [environments](/agent-platform/cloud-agents/environments/)) | No (you manage it) | +| **Session tracking and steering** | Yes | Yes | + +The two architectures are not mutually exclusive. Some teams run managed workers for integration-triggered work and unmanaged agents in CI pipelines. + +## How self-hosting works + +Warp uses a split-plane architecture: **execution happens on your infrastructure**, while **orchestration, session management, and LLM inference route through Warp's backend**. Agent interactions — including code context in session transcripts and LLM prompts — transit Warp's control plane under [Zero Data Retention (ZDR)](/enterprise/security-and-compliance/security-overview/#zero-data-retention-zdr) agreements. Warp does not persistently store your source code or train on it. + +![Self-hosted Oz architecture showing customer-managed execution with Oz orchestration](../../../../../assets/agent-platform/customer-dedicated-saas.png) + +With any self-hosted architecture: + +* **Agent runs are tracked and steerable** — View status, metadata, and session transcripts in the [Oz dashboard](https://oz.warp.dev), the Warp app, or via the [API/SDK](/reference/api-and-sdk/). Authorized teammates can attach to running sessions to monitor or steer agents. +* **Connectivity to Warp's backend is required** — Agents need outbound access to Warp for orchestration, session storage, and LLM inference. No inbound ports need to be opened. +* **Resource limits are controlled by your infrastructure** — Concurrency and compute are only limited by the machines you provision, not by Warp. + +:::note +Enterprise teams that need full control over LLM inference routing can use [Bring Your Own LLM (BYOLLM)](/enterprise/enterprise-features/bring-your-own-llm/) to route inference through their own cloud provider accounts. BYOLLM currently applies to interactive (local) agents; cloud agent support is coming. +::: + +--- + +## Choosing an architecture + +:::caution +**OS support:** The managed architecture is **Linux-only** today (macOS and Windows support is coming). If you need agents to run on macOS or Windows, use the [unmanaged](/agent-platform/cloud-agents/self-hosting/unmanaged/) architecture, which works on any platform Warp supports. +::: + +Use these questions to decide between managed and unmanaged: + +1. **Do you need agents to run on Windows or macOS?** + * Yes → Use the [unmanaged](/agent-platform/cloud-agents/self-hosting/unmanaged/) architecture. Managed is Linux-only today. + * No, Linux works → Continue to the next question. +2. **Do you want Oz to handle starting and stopping agents** (from Slack, the web interface, the Warp app, schedules, or the API)? + * Yes → Use the [managed](#managed-architecture) architecture. + * No, you have your own triggering mechanism → Use the [unmanaged](/agent-platform/cloud-agents/self-hosting/unmanaged/) architecture. +3. **Can your development environment run in a Docker container or Kubernetes pod?** + * Yes, Docker → [Managed: Docker](/agent-platform/cloud-agents/self-hosting/managed-docker/) backend. + * Yes, Kubernetes → [Managed: Kubernetes](/agent-platform/cloud-agents/self-hosting/managed-kubernetes/) backend. + * No (multi-service stacks that don't fit a single container, or environments where container runtimes aren't available) → [Unmanaged](/agent-platform/cloud-agents/self-hosting/unmanaged/) or [Managed: Direct](/agent-platform/cloud-agents/self-hosting/managed-direct/). +4. **Do you have your own orchestrator** (CI/CD, Kubernetes, internal job scheduler) **that starts agents on demand?** + * Yes → [Unmanaged](/agent-platform/cloud-agents/self-hosting/unmanaged/), using `oz agent run` as a drop-in. + * No → [Managed](#managed-architecture). + +### Choosing a managed backend + +The managed architecture supports three backends for task execution: + +1. **Are you deploying the worker into a Kubernetes cluster?** + * Yes → Use the [Kubernetes backend](/agent-platform/cloud-agents/self-hosting/managed-kubernetes/). Each task runs as a Kubernetes Job in your cluster; install with the included Helm chart. + * No → Continue. +2. **Is Docker available on your worker host?** + * Yes → Use the [Docker backend](/agent-platform/cloud-agents/self-hosting/managed-docker/) (default). Tasks run in isolated containers. + * No → Use the [Direct backend](/agent-platform/cloud-agents/self-hosting/managed-direct/). Tasks run directly on the host. +3. **Do you need container-level isolation between tasks?** + * Yes → [Docker](/agent-platform/cloud-agents/self-hosting/managed-docker/) or [Kubernetes](/agent-platform/cloud-agents/self-hosting/managed-kubernetes/) backend. + * No → Any backend works. +4. **Do you need Kubernetes-native scheduling, resource management, or policy enforcement?** + * Yes → [Kubernetes backend](/agent-platform/cloud-agents/self-hosting/managed-kubernetes/). + * No → [Docker](/agent-platform/cloud-agents/self-hosting/managed-docker/) or [Direct](/agent-platform/cloud-agents/self-hosting/managed-direct/) is simpler to set up. + +--- + +## Managed architecture + +With the managed architecture, you run the `oz-agent-worker` daemon on your infrastructure. The daemon connects to Oz's backend, waits for tasks to be assigned to it, and executes those tasks on its host using one of three backends: + +* **[Docker backend](/agent-platform/cloud-agents/self-hosting/managed-docker/)** (default) — Runs each task in an isolated Docker container. +* **[Kubernetes backend](/agent-platform/cloud-agents/self-hosting/managed-kubernetes/)** — Runs each task as a Kubernetes Job in your cluster. +* **[Direct backend](/agent-platform/cloud-agents/self-hosting/managed-direct/)** — Runs each task directly on the host without a container runtime. + +The managed architecture enables full orchestration by Oz — it can remotely start agents via Slack, Linear, the [Oz web app](https://oz.warp.dev), the API/SDK, and the `oz agent run-cloud` command. Agents can access host resources through volume mounts (Docker), Kubernetes-native configuration (Kubernetes), and injected environment variables. + +## Unmanaged architecture + +With the [unmanaged architecture](/agent-platform/cloud-agents/self-hosting/unmanaged/), you run `oz agent run` inside your own orchestrator or dev environment. This works on any platform Warp supports (Linux, macOS, Windows), with no dependency on Docker or any other sandboxing platform. + +You're responsible for executing `oz agent run` on your infrastructure — similar to how you'd integrate Claude Code or Codex CLI. The agent runs directly on the host, which could itself be a Kubernetes pod, VM, container, or CI runner. + +--- + +## Routing runs to self-hosted workers + +This section applies to **all managed backends** (Docker, Kubernetes, and Direct). Once a worker is connected, route Oz cloud agent runs to it by specifying the `--host` flag (or equivalent) with your worker ID. The `--host` value must match the `--worker-id` of a connected worker exactly. + +:::note +Unmanaged runs don't need routing — you invoke `oz agent run` directly on the host where you want the agent to execute. Routing is only relevant for managed workers. +::: + +### From the CLI + +```bash +oz agent run-cloud --prompt "Refactor the authentication module" --host "my-worker" +``` + +You can combine `--host` with any other `run-cloud` flags, such as `--environment`, `--model`, `--mcp`, `--skill`, `--computer-use`, and `--attach`. + +### From scheduled agents + +When creating or updating a schedule, specify the host: + +```bash +oz schedule create --name "daily-cleanup" \ + --cron "0 9 * * *" \ + --prompt "Run dead code cleanup" \ + --environment ENV_ID \ + --host "my-worker" + +oz schedule update SCHEDULE_ID --host "my-worker" +``` + +### From integrations + +When creating or updating an integration, specify the host: + +```bash +oz integration create slack --host "my-worker" ... +oz integration update linear --host "my-worker" ... +``` + +All tasks created through that integration route to your self-hosted worker. + +### From the API and SDKs + +When creating a run via the [Oz API](/reference/api-and-sdk/), include `worker_host` in the config: + +```bash +curl -X POST https://app.warp.dev/api/v1/agent/run \ + --header 'Authorization: Bearer YOUR_API_KEY' \ + --header 'Content-Type: application/json' \ + --data '{ + "prompt": "Refactor the authentication module", + "config": { + "environment_id": "ENV_ID", + "worker_host": "my-worker" + } + }' +``` + +### From the web UI + +When creating a run, schedule, or integration in the [Oz web app](https://oz.warp.dev), select your self-hosted worker from the host dropdown. + +--- + +## Environments with self-hosted workers + +Self-hosted workers fully support [environments](/agent-platform/cloud-agents/environments/). When a task specifies an environment, the worker resolves the Docker image, clones the repositories, runs setup commands, and executes the agent inside the prepared container or Kubernetes Job. + +The same environment can be used for both Warp-hosted and self-hosted runs without modification. See [Environments](/agent-platform/cloud-agents/environments/) for details on creating and configuring them. + +:::note +With the Kubernetes backend, setting a [`default_image`](/agent-platform/cloud-agents/self-hosting/reference/#kubernetes-backend-config) on the worker lets you skip creating a Warp environment when all your tasks use the same base image. +::: + +:::caution +Musl-based Docker images (such as Alpine Linux) are not supported as task images. The agent runtime requires glibc. Use glibc-based images like Debian, Ubuntu, or the default (non-Alpine) variants of official Docker Hub images. +::: + +## Monitoring runs + +Self-hosted runs have the same observability as Warp-hosted runs: + +* **Oz dashboard** — View task status, history, and metadata at [oz.warp.dev](https://oz.warp.dev). +* **Session sharing** — Authorized teammates can attach to running tasks to monitor progress. +* **APIs and SDKs** — Query task history and build monitoring using the [Oz API](/reference/api-and-sdk/). + +For infrastructure-level observability, the `oz-agent-worker` daemon can export OpenTelemetry metrics (worker health, task throughput, capacity saturation) to Prometheus, an OTLP collector, or the console. See [Monitoring](/agent-platform/cloud-agents/self-hosting/monitoring/) for setup, the full metric catalog, and sample PromQL queries. + +--- + +## Related pages + +* [Self-hosting quickstart](/agent-platform/cloud-agents/self-hosting/quickstart/) — Get a managed worker running in ~10 minutes. +* [Unmanaged](/agent-platform/cloud-agents/self-hosting/unmanaged/) — Run `oz agent run` in your CI, K8s, or dev environment. +* [Managed: Docker](/agent-platform/cloud-agents/self-hosting/managed-docker/) — Default managed setup with the Docker backend. +* [Managed: Kubernetes](/agent-platform/cloud-agents/self-hosting/managed-kubernetes/) — Managed setup with the Kubernetes backend and Helm chart. +* [Managed: Direct](/agent-platform/cloud-agents/self-hosting/managed-direct/) — Managed setup with no container runtime. +* [Self-hosted worker reference](/agent-platform/cloud-agents/self-hosting/reference/) — CLI flags and config file schema. +* [Monitoring](/agent-platform/cloud-agents/self-hosting/monitoring/) — OpenTelemetry metrics for worker health, task throughput, and capacity. +* [Security and networking](/agent-platform/cloud-agents/self-hosting/security-and-networking/) — Data boundaries, network egress, and security considerations. +* [Troubleshooting](/agent-platform/cloud-agents/self-hosting/troubleshooting/) — Worker won't start, tasks not picked up, and other common issues. +* [Deployment patterns](/agent-platform/cloud-agents/deployment-patterns/) — How self-hosting compares to CLI-only and Warp-hosted deployment. +* [Environments](/agent-platform/cloud-agents/environments/) — Define the runtime context for agent tasks. diff --git a/src/content/docs/agent-platform/cloud-agents/self-hosting/managed-direct.mdx b/src/content/docs/agent-platform/cloud-agents/self-hosting/managed-direct.mdx new file mode 100644 index 0000000..b2182d9 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/self-hosting/managed-direct.mdx @@ -0,0 +1,128 @@ +--- +title: "Managed: Direct backend" +description: >- + Run the Oz managed worker with the Direct backend to execute cloud agent + tasks directly on the host, without Docker or Kubernetes. +--- + +Run the `oz-agent-worker` daemon with the **Direct backend** — tasks execute directly on the worker host without Docker or Kubernetes. Oz still orchestrates runs end to end (Slack, Linear, schedules, API, `oz agent run-cloud`); the worker just runs the agent in a per-task workspace on its own filesystem. + +:::note +This page covers the [managed architecture](/agent-platform/cloud-agents/self-hosting/#managed-architecture) with the Direct backend. For container-based task isolation, see [Managed: Docker](/agent-platform/cloud-agents/self-hosting/managed-docker/) or [Managed: Kubernetes](/agent-platform/cloud-agents/self-hosting/managed-kubernetes/). For invocation-driven use cases, see [Unmanaged](/agent-platform/cloud-agents/self-hosting/unmanaged/). +::: + +## When to use the Direct backend + +* Neither Docker nor Kubernetes is available on the worker host. +* Tasks need direct access to host resources that are hard to expose through a container. +* You want managed orchestration (triggering from Slack, Linear, schedules, API) without the operational overhead of a container runtime. + +:::caution +The Direct backend does not provide per-task container isolation. Each task runs in an isolated workspace directory, but shares the host OS and kernel. Evaluate whether this fits your security requirements before using it in production. +::: + +--- + +## How it works + +1. The worker creates a per-task workspace directory under `workspace_root`. +2. If a `setup_command` is configured, it runs before the task with environment variables pointing to the workspace. +3. The `oz` CLI runs the agent task inside the workspace directory. +4. After the task completes, the optional `teardown_command` runs and the workspace is cleaned up. + +--- + +## Prerequisites + +* **Enterprise plan with self-hosting enabled** — [Contact sales](https://warp.dev/contact-sales) if self-hosting is not yet enabled for your team. +* **A worker host** with write access to `workspace_root` (defaults to `/var/lib/oz/workspaces`). +* **The Oz CLI** installed and available in `PATH` on the worker host (or specify `oz_path` in the config file). See [Installing the CLI](/reference/cli/#installing-the-cli). +* **A team API key** — In the Warp app, go to **Settings** > **Cloud platform** > **Oz Cloud API Keys** to create a team-scoped API key. See [API Keys](/reference/cli/api-keys/) for details. + +--- + +## Setup + +### 1. Set your API key + +Export the API key so the worker can authenticate to Oz: + +```bash +export WARP_API_KEY="your_team_api_key" +``` + +### 2. Start the worker with the Direct backend + +Pass `--backend direct`: + +```bash +oz-agent-worker --api-key "$WARP_API_KEY" --worker-id "my-worker" --backend direct +``` + +Or with a [config file](/agent-platform/cloud-agents/self-hosting/reference/#config-file): + +```yaml +worker_id: "my-worker" +backend: + direct: + workspace_root: "/var/lib/oz/workspaces" +``` + +**Expected outcome:** The worker connects to Oz and begins listening for tasks. Each assigned task runs in a freshly-created subdirectory of `workspace_root`. + +--- + +## Workspace model + +Each task gets its own directory under `workspace_root`. The default is `/var/lib/oz/workspaces`; override it with the `workspace_root` config option shown above. + +After the task completes, the workspace is deleted (unless `--no-cleanup` is set, which keeps the directory around for debugging). + +--- + +## Setup and teardown commands + +The `setup_command` runs before each task and receives the following environment variables: + +* `OZ_WORKSPACE_ROOT` — The workspace directory for the task. +* `OZ_RUN_ID` — The unique task ID. +* `OZ_ENVIRONMENT_FILE` — Path to a file where the setup script can write additional `KEY=VALUE` environment variables to inject into the task. +* `OZ_WORKER_BACKEND` — Always set to `direct`. + +The `teardown_command` runs after each task and receives `OZ_WORKSPACE_ROOT`, `OZ_RUN_ID`, and `OZ_WORKER_BACKEND`. + +Use the setup command to clone repos, install dependencies, or write task-specific env vars into `OZ_ENVIRONMENT_FILE`. Use the teardown command for cleanup or reporting. + +--- + +## Environment variables for Direct tasks + +:::note +The Direct backend starts tasks with a **minimal environment** (only `HOME`, `TMPDIR`, and `PATH` from the host) to avoid leaking sensitive worker credentials like `WARP_API_KEY` into tasks. Add variables explicitly via `environment` in the config file or `-e` flags on the worker CLI. +::: + +Config file example: + +```yaml +worker_id: "direct-worker" +max_concurrent_tasks: 2 +backend: + direct: + workspace_root: "/var/lib/oz/workspaces" + oz_path: "/usr/local/bin/oz" + setup_command: "/opt/scripts/setup.sh" + teardown_command: "/opt/scripts/teardown.sh" + environment: + - name: MY_VAR + value: "hello" +``` + +--- + +## Related pages + +* [Self-hosted worker reference](/agent-platform/cloud-agents/self-hosting/reference/#direct-backend-config) — Full config schema for the Direct backend. +* [Self-hosting overview](/agent-platform/cloud-agents/self-hosting/) — Managed vs unmanaged and the backend decision guide. +* [Routing runs to self-hosted workers](/agent-platform/cloud-agents/self-hosting/#routing-runs-to-self-hosted-workers) — How to send tasks to your connected worker from the CLI, schedules, integrations, the API, and the web UI. +* [Security and networking](/agent-platform/cloud-agents/self-hosting/security-and-networking/) — Data boundaries and security considerations for the Direct backend. +* [Troubleshooting](/agent-platform/cloud-agents/self-hosting/troubleshooting/#direct-backend) — Common Direct-backend issues. diff --git a/src/content/docs/agent-platform/cloud-agents/self-hosting/managed-docker.mdx b/src/content/docs/agent-platform/cloud-agents/self-hosting/managed-docker.mdx new file mode 100644 index 0000000..c3bcd0b --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/self-hosting/managed-docker.mdx @@ -0,0 +1,215 @@ +--- +title: "Managed: Docker backend" +description: >- + Run the Oz managed worker daemon with the Docker backend to execute cloud + agent tasks in isolated containers on your infrastructure. +--- + +Run the `oz-agent-worker` daemon with the **Docker backend** — the default managed path. Each agent task runs in an isolated Docker container spawned from the worker, with full orchestration by Oz (Slack, Linear, schedules, API, `oz agent run-cloud`). + +:::note +This page covers the [managed architecture](/agent-platform/cloud-agents/self-hosting/#managed-architecture) with the Docker backend. For the Kubernetes backend, see [Managed: Kubernetes](/agent-platform/cloud-agents/self-hosting/managed-kubernetes/). For host execution without a container runtime, see [Managed: Direct](/agent-platform/cloud-agents/self-hosting/managed-direct/). If you'd rather invoke agents yourself, see [Unmanaged](/agent-platform/cloud-agents/self-hosting/unmanaged/). +::: + +## When to use the Docker backend + +* You want the simplest managed setup and have Docker available on the worker host. +* You want per-task isolation without running a Kubernetes cluster. +* You're not already deploying workloads into Kubernetes. + +--- + +## Prerequisites + +* **Enterprise plan with self-hosting enabled** — [Contact sales](https://warp.dev/contact-sales) if self-hosting is not yet enabled for your team. +* **A machine to run the worker** — A VM, server, or local machine running Linux (recommended for production). For testing, macOS and Windows hosts running Docker Desktop work. +* **Docker installed** — The worker uses Docker to spawn task containers. The Docker daemon must run Linux containers (Windows containers are not supported). Verify with `docker info`. +* **A team API key** — In the Warp app, go to **Settings** > **Cloud platform** > **Oz Cloud API Keys** to create a team-scoped API key. See [API Keys](/reference/cli/api-keys/) for details. + +:::caution +Task containers require a **linux/amd64** or **linux/arm64** Docker daemon. The worker host itself can be any OS — Docker Desktop on macOS and Windows runs a Linux VM that satisfies this requirement. +::: + +### Install Docker + +If Docker is not already installed, follow the [official Docker installation guide](https://docs.docker.com/get-docker/) for your platform. Verify Docker is running: + +```bash +docker info +``` + +**Expected outcome:** `docker info` prints daemon details without errors. + +--- + +## Set your API key + +Export your team API key so the worker can authenticate to Oz: + +```bash +export WARP_API_KEY="your_team_api_key" +``` + +## Install and run the worker + +The `oz-agent-worker` is open source. See the [oz-agent-worker repository](https://github.com/warpdotdev/oz-agent-worker) for source code, issues, and contribution guidelines. + +There are three ways to install and run the worker with the Docker backend. Docker is recommended for production; `go install` and building from source are primarily useful for contributors and one-off testing. + +The worker can be configured entirely via CLI flags, or via a YAML [config file](/agent-platform/cloud-agents/self-hosting/reference/#config-file) for more complex setups. + +### Option 1: Docker (recommended) + +The worker needs access to the Docker daemon to spawn task containers. Mount the host's Docker socket into the worker container: + +```bash +docker run -v /var/run/docker.sock:/var/run/docker.sock \ + -e WARP_API_KEY="$WARP_API_KEY" \ + warpdotdev/oz-agent-worker --worker-id "my-worker" +``` + +**Expected outcome:** The worker connects to Oz and logs that it's listening for tasks. + +### Option 2: Go install + +```bash +go install github.com/warpdotdev/oz-agent-worker@latest +oz-agent-worker --api-key "$WARP_API_KEY" --worker-id "my-worker" +``` + +### Option 3: Build from source + +```bash +git clone https://github.com/warpdotdev/oz-agent-worker.git +cd oz-agent-worker +go build -o oz-agent-worker +./oz-agent-worker --api-key "$WARP_API_KEY" --worker-id "my-worker" +``` + +Once started, the worker connects to Oz, waits for tasks routed to its `--worker-id`, runs each task in an isolated Docker container, and reports status and results back. The worker automatically reconnects if the connection drops. + +You can run multiple workers with the same `--worker-id` for redundancy — Oz distributes tasks across connected workers. + +--- + +## Docker backend configuration + +The worker can take configuration either via CLI flags or via a YAML [config file](/agent-platform/cloud-agents/self-hosting/reference/#config-file). CLI flags take precedence over config file values. + +**Common CLI flags:** + +```bash +docker run -v /var/run/docker.sock:/var/run/docker.sock \ + -e WARP_API_KEY="$WARP_API_KEY" \ + warpdotdev/oz-agent-worker \ + --worker-id "prod-runner-1" \ + --log-level debug \ + --max-concurrent-tasks 4 \ + --idle-on-complete 10m \ + -v /opt/shared-cache:/cache:ro \ + -e NPM_TOKEN=your_token \ + -e GITHUB_TOKEN +``` + +:::caution +When running the worker via Docker, there are two levels of `-e` flags. Docker's `-e` passes env vars to the **worker container** (e.g., `WARP_API_KEY`). The worker's `-e` / `--env` flags pass env vars into the **task containers** the worker spawns. Keep these distinct: + +```bash +# Docker -e: passes WARP_API_KEY to the worker container +# Worker -e: passes MY_SECRET to task containers +docker run \ + -e WARP_API_KEY="$WARP_API_KEY" \ + warpdotdev/oz-agent-worker \ + --worker-id "my-worker" \ + -e MY_SECRET=hunter2 +``` +::: + +**Equivalent config file** (`config.yaml`): + +```yaml +worker_id: "prod-runner-1" +log_level: "debug" +max_concurrent_tasks: 4 +idle_on_complete: "10m" +backend: + docker: + volumes: + - "/opt/shared-cache:/cache:ro" + environment: + - name: NPM_TOKEN + value: "your_token" + - name: GITHUB_TOKEN # inherits from host environment +``` + +Pass it with `--config-file config.yaml`. See the [self-hosted worker reference](/agent-platform/cloud-agents/self-hosting/reference/) for the full flag and config schema. + +--- + +## Docker connectivity + +The worker uses the standard Docker client discovery mechanism to find the Docker daemon: + +1. **`DOCKER_HOST`** environment variable (e.g., `unix:///var/run/docker.sock`, `tcp://localhost:2375`). +2. **Default socket** (`/var/run/docker.sock` on Linux, `~/.docker/run/docker.sock` for rootless Docker). +3. **Docker context** via `DOCKER_CONTEXT` environment variable. +4. **Config file** (`~/.docker/config.json`) for context settings. + +Additional Docker environment variables the worker respects: + +* `DOCKER_API_VERSION` — Specify Docker API version. +* `DOCKER_CERT_PATH` — Path to TLS certificates. +* `DOCKER_TLS_VERIFY` — Enable TLS verification. + +:::note +If the worker itself runs in Docker, you must mount any relevant config files (e.g., `~/.docker/config.json`) into the worker container for Docker context and credential discovery to work. +::: + +**Example: Connecting to a remote Docker daemon** + +```bash +export DOCKER_HOST="tcp://remote-host:2376" +export DOCKER_TLS_VERIFY=1 +export DOCKER_CERT_PATH="/path/to/certs" +oz-agent-worker --api-key "$WARP_API_KEY" --worker-id "my-worker" +``` + +--- + +## Private Docker registries + +The worker automatically uses credentials from your Docker config (`~/.docker/config.json`) when pulling task images. If your [environments](/agent-platform/cloud-agents/environments/) use images from a private registry, authenticate the worker's host first: + +```bash +docker login your-registry.example.com +``` + +When running the worker via Docker, mount the Docker config into the container: + +```bash +docker run \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v ~/.docker/config.json:/root/.docker/config.json:ro \ + -e WARP_API_KEY="$WARP_API_KEY" \ + warpdotdev/oz-agent-worker --worker-id "my-worker" +``` + +:::note +Sidecar images (the `oz` binary and dependencies) are pulled from public registries and do not require authentication. +::: + +--- + +## Routing runs to this worker + +Once your Docker worker is connected, route tasks to it with `--host "<your-worker-id>"`. Routing is the same across all managed backends — see [Routing runs to self-hosted workers](/agent-platform/cloud-agents/self-hosting/#routing-runs-to-self-hosted-workers) for CLI, scheduled, integration, API, and web UI examples. + +--- + +## Related pages + +* [Self-hosting quickstart](/agent-platform/cloud-agents/self-hosting/quickstart/) — ~10-minute path to a running Docker worker. +* [Self-hosted worker reference](/agent-platform/cloud-agents/self-hosting/reference/) — Full CLI flag and config file schema. +* [Environments](/agent-platform/cloud-agents/environments/) — Define the Docker image, repos, and setup commands for tasks. +* [Security and networking](/agent-platform/cloud-agents/self-hosting/security-and-networking/) — Data boundaries, egress, and Docker socket considerations. +* [Troubleshooting](/agent-platform/cloud-agents/self-hosting/troubleshooting/) — Common issues with the Docker backend. diff --git a/src/content/docs/agent-platform/cloud-agents/self-hosting/managed-kubernetes.mdx b/src/content/docs/agent-platform/cloud-agents/self-hosting/managed-kubernetes.mdx new file mode 100644 index 0000000..cfdf77a --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/self-hosting/managed-kubernetes.mdx @@ -0,0 +1,272 @@ +--- +title: "Managed: Kubernetes backend" +description: >- + Deploy the Oz managed worker into a Kubernetes cluster with the included + Helm chart. Each agent task runs as a Kubernetes Job in your cluster. +--- + +Deploy the `oz-agent-worker` daemon into a Kubernetes cluster using the included Helm chart. Each agent task runs as a **Kubernetes Job** in your cluster. Oz orchestrates runs end to end (Slack, Linear, schedules, API, `oz agent run-cloud`); your cluster provides the compute, scheduling, and policy enforcement. + +:::note +This page covers the [managed architecture](/agent-platform/cloud-agents/self-hosting/#managed-architecture) with the Kubernetes backend. For the default Docker backend, see [Managed: Docker](/agent-platform/cloud-agents/self-hosting/managed-docker/). For host execution without a container runtime, see [Managed: Direct](/agent-platform/cloud-agents/self-hosting/managed-direct/). To route runs to a connected worker, see [Routing runs to self-hosted workers](/agent-platform/cloud-agents/self-hosting/managed-docker/#routing-runs-to-self-hosted-workers). +::: + +## When to use the Kubernetes backend + +* You already operate a Kubernetes cluster and want agents to run there. +* You need Kubernetes-native scheduling, resource management, or policy enforcement. +* You want to use Kubernetes Secrets, ServiceAccounts, and admission policies to control task behavior. + +--- + +## How it works + +1. The worker connects to the Kubernetes API server (using in-cluster auth by default, or an explicit kubeconfig). +2. On startup, the worker runs a short-lived **preflight Job** to verify that cluster permissions, admission policies, and Pod Security Standards are compatible. If the preflight fails, the worker exits with a diagnostic error before accepting any tasks. +3. For each assigned task, the worker creates a Kubernetes Job in the configured namespace. +4. The worker monitors the Job and Pod status via Kubernetes Watch (with a 30-second safety-net poll for watch disconnects). +5. After the task completes, the Job is cleaned up (unless `--no-cleanup` is set). + +--- + +## Prerequisites + +* **Enterprise plan with self-hosting enabled** — [Contact sales](https://warp.dev/contact-sales) if self-hosting is not yet enabled for your team. +* **A Kubernetes cluster** with the worker process able to reach the API server. The cluster must: + * Allow the worker's namespace to create Jobs with a **root init container** (sidecar materialization depends on this pattern). + * Grant the worker these namespace-scoped permissions: `create`, `get`, `list`, `watch`, `delete` on `jobs`; `get`, `list`, `watch` on `pods`; `get` on `pods/log`; `list` on `events`. +* **[Helm](https://helm.sh/docs/intro/install/)** installed locally, plus `kubectl` authenticated against the target cluster. +* **A team API key** — In the Warp app, go to **Settings** > **Cloud platform** > **Oz Cloud API Keys** to create a team-scoped API key. See [API Keys](/reference/cli/api-keys/) for details. + +--- + +## Install with the Helm chart + +The `oz-agent-worker` repository includes a namespace-scoped Helm chart at `charts/oz-agent-worker`. This is the recommended way to deploy the worker into a cluster. + +### What the chart deploys + +* A long-lived `Deployment` running `oz-agent-worker` with the Kubernetes backend. +* A namespaced `ServiceAccount` for the worker. +* A namespaced `Role` / `RoleBinding` with the minimum permissions needed to manage task Jobs and Pods. +* A `ConfigMap` containing the worker config YAML. +* An optional `Secret` for `WARP_API_KEY` (or a reference to an existing Secret). + +The chart does not create CRDs or cluster-scoped RBAC resources. + +### 1. Set your API key and namespace + +```bash +export WARP_API_KEY="your_team_api_key" +``` + +Create the namespace if it doesn't exist: + +```bash +kubectl create namespace warp-oz +``` + +### 2. Create the API key Secret + +If you're not using an existing Secret, create one with the API key: + +```bash +kubectl create secret generic oz-agent-worker \ + --from-literal=WARP_API_KEY="$WARP_API_KEY" \ + --namespace warp-oz +``` + +**Expected outcome:** `kubectl get secret -n warp-oz oz-agent-worker` shows the Secret. + +### 3. Install the chart + +Clone the worker repo and install the chart: + +```bash +git clone https://github.com/warpdotdev/oz-agent-worker.git + +helm install oz-agent-worker ./oz-agent-worker/charts/oz-agent-worker \ + --namespace warp-oz \ + --set worker.workerId=oz-k8s-worker \ + --set image.tag=<version> +``` + +:::caution +Set `image.tag` explicitly to pin the worker image. Check the [oz-agent-worker releases](https://github.com/warpdotdev/oz-agent-worker/releases) for the latest version. Do not rely on `latest`. +::: + +**Expected outcome:** `kubectl get pods -n warp-oz` shows the worker Deployment pod as `Running`, and the worker logs show `Connected to Oz` / `Listening for tasks`. + +To scale horizontally, deploy multiple Helm releases with distinct worker IDs rather than increasing replicas on a single release. + +--- + +## Key chart values + +**Required:** + +* `worker.workerId` — The worker ID (same as `--worker-id`). +* `image.tag` — The worker image tag to deploy. + +**Worker configuration:** + +* `worker.logLevel` — Log verbosity (`debug`, `info`, `warn`, `error`). Defaults to `info`. +* `worker.cleanup` — Whether to clean up task Jobs after execution. Defaults to `true`. +* `worker.maxConcurrentTasks` — Maximum concurrent tasks. Defaults to `0` (unlimited). +* `worker.idleOnComplete` — Duration to keep the oz process alive after task completion. +* `worker.resources` — Resource requests/limits for the worker Deployment. Defaults to `100m` CPU and `128Mi` memory. +* `worker.livenessProbe` — Liveness probe for the worker Deployment. Defaults to an `exec` probe (`kill -0 1`). Override with a custom probe or set to `null` to disable. +* `worker.nodeSelector`, `worker.tolerations`, `worker.affinity` — Scheduling constraints for the worker Deployment pod. + +**Kubernetes backend:** + +* `kubernetesBackend.namespace` — Namespace for task Jobs. Defaults to the release namespace. +* `kubernetesBackend.defaultImage` — Default Docker image for task pods when the run has no Warp environment image. Leave empty (default) to fall back to `ubuntu:22.04`. +* `kubernetesBackend.imagePullPolicy` — Image pull policy for task pods. Defaults to `IfNotPresent`. +* `kubernetesBackend.preflightImage` — Image for the startup preflight Job. Set this if your cluster restricts allowed registries. +* `kubernetesBackend.unschedulableTimeout` — How long a pod may remain unschedulable before failing. Defaults to `30s`. +* `kubernetesBackend.setupCommand` — Shell command to run before each task. +* `kubernetesBackend.teardownCommand` — Shell command to run after each task. +* `kubernetesBackend.extraLabels` — Additional labels for task Jobs and Pods. +* `kubernetesBackend.extraAnnotations` — Additional annotations for task Jobs and Pods. +* `kubernetesBackend.activeDeadlineSeconds` — Maximum task Job lifetime. +* `kubernetesBackend.workspaceSizeLimit` — Size limit for workspace `emptyDir` volume. +* `kubernetesBackend.podTemplate` — Raw PodSpec YAML for task Jobs (same as `backend.kubernetes.pod_template` in the [config file](/agent-platform/cloud-agents/self-hosting/reference/#config-file)). + +**API key Secret:** + +* `warp.apiKeySecret.create` — Set to `true` to have the chart create a Secret from `warp.apiKeySecret.value`. Defaults to `false` (expects a pre-existing Secret). +* `warp.apiKeySecret.value` — The API key value to store in the chart-managed Secret. Only used when `warp.apiKeySecret.create` is `true`. +* `warp.apiKeySecret.name` — Name of the Secret containing `WARP_API_KEY`. Defaults to `oz-agent-worker`. +* `warp.apiKeySecret.key` — Key within the Secret. Defaults to `WARP_API_KEY`. + +See the [self-hosted worker reference](/agent-platform/cloud-agents/self-hosting/reference/#kubernetes-backend-config) for the full config file schema. + +--- + +## Cluster selection + +Cluster selection follows Kubernetes client config conventions: + +* Set `backend.kubernetes.kubeconfig` to use an explicit kubeconfig file. +* If `kubeconfig` is omitted and the worker runs inside a Kubernetes pod, the worker uses in-cluster config automatically. +* Otherwise, the worker falls back to the default kubeconfig loading rules and uses the current context. + +`namespace` selects the namespace inside the chosen cluster. It defaults to `default` when omitted. + +--- + +## Pod template + +The `pod_template` field accepts standard Kubernetes PodSpec YAML and is the declarative way to configure task pod scheduling, service accounts, image pull secrets, resources, and environment variables. + +When using `pod_template`, define a container named `task` to customize the main task container directly. Otherwise, the worker appends its own `task` container to the PodSpec. + +Use `valueFrom.secretKeyRef` to inject Kubernetes Secret values into task container environment variables: + +```yaml +pod_template: + serviceAccountName: agent-task-sa + imagePullSecrets: + - name: my-registry-creds + containers: + - name: task + resources: + requests: + cpu: "2" + memory: 4Gi + limits: + memory: 8Gi + env: + - name: GITHUB_TOKEN + valueFrom: + secretKeyRef: + name: my-k8s-secret + key: github-token + tolerations: + - key: "dedicated" + operator: "Equal" + value: "agents" + effect: "NoSchedule" +``` + +:::note +The worker Deployment's ServiceAccount is separate from the task Job `serviceAccountName` you configure in `pod_template`. The Deployment ServiceAccount needs RBAC to manage Jobs and Pods. The task ServiceAccount (if any) controls what the agent process can access at runtime. +::: + +--- + +## Preflight check + +On startup, the worker creates a short-lived preflight Job to verify that: + +* The worker has sufficient RBAC permissions in the target namespace. +* Cluster admission policies (Pod Security Standards, OPA Gatekeeper, Kyverno, etc.) allow the worker's task pod shape. +* The preflight image can be pulled. + +If the preflight fails, the worker logs a diagnostic error and exits before accepting any tasks. This surfaces policy and configuration issues at deploy time rather than at task execution time. + +The preflight image defaults to `busybox:1.36`. If your cluster restricts allowed registries or images, set `preflight_image` to an allowlisted image. When `imagePullSecrets` is configured in `pod_template`, those secrets apply to the preflight Job as well, so you can point `preflight_image` at an image in your private registry. + +--- + +## Environment variables for Kubernetes tasks + +There are two ways to pass environment variables to Kubernetes task containers: + +1. **`pod_template`** (recommended for Kubernetes-native config) — Use standard Kubernetes `env` syntax in the `task` container, including `valueFrom.secretKeyRef` for Kubernetes Secrets. +2. **`-e` / `--env` flags** — Backend-agnostic runtime overrides that work across all managed backends. + +When configuring the Kubernetes backend via YAML or Helm, declarative task-container env belongs in `pod_template` rather than a separate top-level list. + +:::note +If your organization uses an external secrets manager (HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, etc.), you can inject secrets into task pods via the CSI Secrets Store Driver or a similar operator. Configure the required `volumes`, `volumeMounts`, and annotations in `pod_template` just as you would for any other Kubernetes workload. See your secrets provider's documentation for details. +::: + +--- + +## Setup and teardown commands + +Use `kubernetesBackend.setupCommand` (Helm value) or `backend.kubernetes.setup_command` ([config file](/agent-platform/cloud-agents/self-hosting/reference/#kubernetes-backend-config)) to run a shell command before each task. Use `teardownCommand` / `teardown_command` for cleanup after the task finishes. These run inside the task Pod and are useful for workspace bootstrapping or post-run reporting. + +--- + +## Metrics + +The Helm chart includes built-in support for exporting OpenTelemetry metrics from the worker. Enable metrics by setting `metrics.enabled=true`: + +```bash +helm install oz-agent-worker ./charts/oz-agent-worker \ + --namespace warp-oz \ + --set worker.workerId=oz-k8s-worker \ + --set image.tag=VERSION \ + --set metrics.enabled=true +``` + +With the default `metrics.exporter=prometheus`, the chart creates a `Service` with Prometheus scrape annotations and exposes port `9464`. For clusters using the Prometheus Operator, set `metrics.podMonitor.create=true` to create a `PodMonitor`. + +To push metrics to an OTLP collector instead, set `metrics.exporter=otlp` and configure the endpoint via `metrics.extraEnv`. + +See [Monitoring](/agent-platform/cloud-agents/self-hosting/monitoring/) for the full list of Helm values, the metric catalog, and sample PromQL queries. + +--- + +## Operational notes + +* **Scaling** — The chart always deploys a single replica for a given `worker.workerId`. To run multiple workers, deploy multiple Helm releases with distinct worker IDs rather than scaling a single release horizontally. +* **Security context** — The Deployment defaults to a non-root security context (`runAsUser: 10001`) with `allowPrivilegeEscalation: false` and all capabilities dropped. +* **Liveness probe** — The Deployment includes a default `exec` liveness probe (`kill -0 1`). Override `worker.livenessProbe` for a custom probe, or set it to `null` to disable. +* **In-cluster auth** — The chart assumes the worker runs inside the target cluster and uses in-cluster Kubernetes auth by default. +* **Root init containers** — The worker Deployment itself is non-root, but task Jobs require a root init container for sidecar materialization. Ensure the task namespace's Pod Security Standards allow this. + +--- + +## Related pages + +* [Self-hosted worker reference](/agent-platform/cloud-agents/self-hosting/reference/) — Full CLI flag and config file schema, including every Kubernetes backend field. +* [Self-hosting overview](/agent-platform/cloud-agents/self-hosting/) — Managed vs unmanaged and the backend decision guide. +* [Routing runs to self-hosted workers](/agent-platform/cloud-agents/self-hosting/#routing-runs-to-self-hosted-workers) — How to send tasks to your connected worker from the CLI, schedules, integrations, the API, and the web UI. +* [Environments](/agent-platform/cloud-agents/environments/) — Define the task image, repos, and setup commands. +* [Monitoring](/agent-platform/cloud-agents/self-hosting/monitoring/) — OpenTelemetry metrics, including Helm chart metrics values. +* [Security and networking](/agent-platform/cloud-agents/self-hosting/security-and-networking/) — RBAC, admission policies, and data boundaries. +* [Troubleshooting](/agent-platform/cloud-agents/self-hosting/troubleshooting/#kubernetes-backend) — Common Kubernetes-backend issues. diff --git a/src/content/docs/agent-platform/cloud-agents/self-hosting/monitoring.mdx b/src/content/docs/agent-platform/cloud-agents/self-hosting/monitoring.mdx new file mode 100644 index 0000000..d83356a --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/self-hosting/monitoring.mdx @@ -0,0 +1,224 @@ +--- +title: Monitoring +description: >- + Monitor self-hosted Oz workers with OpenTelemetry metrics. Export to + Prometheus, OTLP, or console to track worker health, task throughput, + and saturation. +--- + +The `oz-agent-worker` daemon exports infrastructure-level metrics over [OpenTelemetry](https://opentelemetry.io/), giving your team real-time visibility into worker health, task throughput, and capacity. Combine these metrics with the [Oz dashboard](https://oz.warp.dev) for full observability across both the orchestration plane and your self-hosted compute. + +:::note +When running the binary directly, metrics export follows the [OpenTelemetry autoexport](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/exporters/autoexport) default — if `OTEL_METRICS_EXPORTER` is unset, the worker pushes OTLP to `localhost:4318`. Set `OTEL_METRICS_EXPORTER=none` to disable export. The Helm chart is opt-in: it only enables export when `metrics.enabled=true`. +::: + +## Key features + +* **Prometheus scrape** — Expose a `/metrics` endpoint for Prometheus to scrape, with optional `PodMonitor` support for the Prometheus Operator. +* **OTLP push** — Push metrics to any OpenTelemetry-compatible collector (Grafana Alloy, Datadog Agent, New Relic, etc.). +* **Standard configuration** — Exporter selection uses the standard [OpenTelemetry environment variables](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/), so the worker integrates with your existing observability stack without custom configuration. +* **Pre-seeded series** — All metric series appear at startup (before any tasks run), so dashboards and alerts can reference them immediately. + +## How it works + +The worker uses the [`go.opentelemetry.io/contrib/exporters/autoexport`](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/exporters/autoexport) package to select an exporter at runtime based on the `OTEL_METRICS_EXPORTER` environment variable. Supported values: + +* `prometheus` — Starts an in-process HTTP server serving `/metrics`. +* `otlp` — Pushes metrics over OTLP (HTTP/protobuf by default). +* `console` — Writes metrics to stdout (useful for debugging). +* `none` — Disables metrics export entirely. + +When `OTEL_METRICS_EXPORTER` is unset, the worker defaults to OTLP push targeting `OTEL_EXPORTER_OTLP_ENDPOINT` (which itself defaults to `http://localhost:4318` for `http/protobuf` or `http://localhost:4317` for `grpc`). + +All metrics carry resource attributes (`service.name=oz-agent-worker`, `service.version`, `worker.id`, `worker.backend`) so each worker process shows up as a distinct series in your monitoring system. + +--- + +## Enable Prometheus scrape + +Set these environment variables before starting the worker to expose a Prometheus-compatible `/metrics` endpoint: + +```bash +export OTEL_METRICS_EXPORTER=prometheus +export OTEL_EXPORTER_PROMETHEUS_HOST=0.0.0.0 +export OTEL_EXPORTER_PROMETHEUS_PORT=9464 +oz-agent-worker --api-key "$WARP_API_KEY" --worker-id "my-worker" +``` + +Verify the endpoint is serving metrics: + +```bash +curl -s localhost:9464/metrics | grep oz_worker_ +``` + +**Expected outcome:** You see `oz_worker_connected`, `oz_worker_tasks_active`, and other `oz_worker_*` metric families in the output. + +:::note +Bind to `0.0.0.0` (not `localhost`) when running in Docker or Kubernetes so the Prometheus server, kubelet, or scrape target can reach the endpoint from outside the container. +::: + +--- + +## Enable OTLP push + +Set these environment variables to push metrics to an OpenTelemetry collector: + +```bash +export OTEL_METRICS_EXPORTER=otlp +export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf +export OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector.observability.svc:4318 +oz-agent-worker --api-key "$WARP_API_KEY" --worker-id "my-worker" +``` + +The worker pushes metrics at the SDK's default interval. Configure the collector endpoint, protocol, and headers using standard [OTLP exporter environment variables](https://opentelemetry.io/docs/specs/otel/protocol/exporter/). + +--- + +## Helm chart configuration + +The [Helm chart](/agent-platform/cloud-agents/self-hosting/managed-kubernetes/) includes built-in support for metrics. Enable metrics with `metrics.enabled=true`: + +```bash +helm install oz-agent-worker ./charts/oz-agent-worker \ + --namespace warp-oz \ + --set worker.workerId=my-worker \ + --set image.tag=VERSION \ + --set metrics.enabled=true +``` + +With `metrics.enabled=true` and the default `metrics.exporter=prometheus`, the chart adds: + +* A `containerPort: metrics` (default 9464) on the worker Deployment. +* The `OTEL_METRICS_EXPORTER`, `OTEL_EXPORTER_PROMETHEUS_HOST`, and `OTEL_EXPORTER_PROMETHEUS_PORT` environment variables. +* A namespace-scoped `Service` named `<release>-oz-agent-worker-metrics` with `prometheus.io/scrape` annotations. +* Optionally, a `PodMonitor` (`metrics.podMonitor.create=true`) for clusters using the Prometheus Operator. + +### Helm values + +**Core:** + +* `metrics.enabled` — Enable metrics export. Defaults to `false`. +* `metrics.exporter` — Exporter type: `prometheus` (default), `otlp`, `console`, or `none`. +* `metrics.port` — Port for the Prometheus exporter. Defaults to `9464`. Ignored for `otlp`/`console`. +* `metrics.extraEnv` — Extra environment variables for the worker container (e.g., `OTEL_EXPORTER_OTLP_ENDPOINT`). + +**Service (Prometheus scrape):** + +* `metrics.service.create` — Create a metrics `Service`. Defaults to `true`. +* `metrics.service.type` — Service type. Defaults to `ClusterIP`. +* `metrics.service.annotations` — Annotations on the Service. Defaults include `prometheus.io/scrape: "true"`. + +**PodMonitor (Prometheus Operator):** + +* `metrics.podMonitor.create` — Create a `PodMonitor`. Defaults to `false` (avoids requiring `monitoring.coreos.com` CRDs). +* `metrics.podMonitor.interval` — Scrape interval. Defaults to `30s`. +* `metrics.podMonitor.scrapeTimeout` — Scrape timeout. Defaults to `10s`. +* `metrics.podMonitor.additionalLabels` — Extra labels on the `PodMonitor` resource. + +### OTLP push via Helm + +To push metrics to an OTLP collector instead of exposing a Prometheus endpoint, set `metrics.exporter=otlp` and forward the endpoint via `metrics.extraEnv`: + +```yaml +metrics: + enabled: true + exporter: otlp + extraEnv: + - name: OTEL_EXPORTER_OTLP_ENDPOINT + value: http://otel-collector.observability.svc:4318 +``` + +--- + +## Metric catalog + +All metrics use the `oz_worker_` prefix. Each worker process emits a distinct set of series, identified by the resource attributes `service.name`, `service.version`, `worker.id`, and `worker.backend`. + +* **`oz_worker_connected`** (gauge) — `1` while the worker has an active WebSocket connection to Oz's backend, `0` otherwise. +* **`oz_worker_tasks_active`** (gauge / UpDownCounter) — Tasks currently executing on this worker. +* **`oz_worker_tasks_max_concurrent`** (gauge) — Configured concurrency limit (`0` means unlimited). +* **`oz_worker_tasks_claimed_total`** (counter) — Total tasks accepted since process start. +* **`oz_worker_tasks_rejected_total{reason}`** (counter) — Tasks the worker declined (e.g., `reason="at_capacity"`). +* **`oz_worker_tasks_completed_total{result}`** (counter) — Completed tasks labeled `result="succeeded"` or `result="failed"`. +* **`oz_worker_task_duration_seconds{result}`** (histogram) — Wall-clock task duration on the worker, labeled by result. +* **`oz_worker_websocket_reconnects_total{reason}`** (counter) — WebSocket reconnect attempts (e.g., `reason="dial_failed"`, `reason="remote_close"`). Spikes indicate flapping workers. +* **`oz_worker_info{version,backend,worker_id}`** (gauge, constant `1`) — Build and runtime metadata. Useful for joining other series by labels. + +--- + +## Sample PromQL queries + +Direct mappings for common operational questions: + +* **Workers available:** + + ```promql + sum(oz_worker_connected) + ``` + +* **Workers active (running at least one task):** + + ```promql + count(oz_worker_tasks_active > 0) + ``` + +* **Fleet saturation:** + + ```promql + sum(oz_worker_tasks_active) / sum(oz_worker_tasks_max_concurrent > 0) + ``` + + This ratio is only meaningful when every worker has a non-zero `oz_worker_tasks_max_concurrent`. Workers configured with `0` (unlimited) are excluded from the denominator, which can make the saturation result look misleadingly high or undefined for fleets that mix bounded and unlimited workers. + +* **Task success rate (5-minute window):** + + ```promql + sum(rate(oz_worker_tasks_completed_total{result="succeeded"}[5m])) + / sum(rate(oz_worker_tasks_completed_total[5m])) + ``` + +* **Task duration p95:** + + ```promql + histogram_quantile(0.95, sum by (le) (rate(oz_worker_task_duration_seconds_bucket[5m]))) + ``` + +* **Failure rate:** + + ```promql + sum(rate(oz_worker_tasks_completed_total{result="failed"}[5m])) + ``` + +* **Reconnect storms (alert threshold):** + + ```promql + sum(rate(oz_worker_websocket_reconnects_total[5m])) > 0.1 + ``` + +--- + +## Disabling metrics + +To fully disable metrics export, set `OTEL_METRICS_EXPORTER=none`: + +```bash +export OTEL_METRICS_EXPORTER=none +oz-agent-worker --api-key "$WARP_API_KEY" --worker-id "my-worker" +``` + +Or in the Helm chart: + +```yaml +metrics: + enabled: false +``` + +--- + +## Related pages + +* [Self-hosting overview](/agent-platform/cloud-agents/self-hosting/) — Architecture, decision guide, and Enterprise requirements. +* [Self-hosted worker reference](/agent-platform/cloud-agents/self-hosting/reference/) — CLI flags, config file schema, and metrics environment variables. +* [Managed: Kubernetes](/agent-platform/cloud-agents/self-hosting/managed-kubernetes/) — Helm chart deployment, including metrics values. +* [Troubleshooting](/agent-platform/cloud-agents/self-hosting/troubleshooting/) — Diagnostics for metrics issues and other common problems. +* [Security and networking](/agent-platform/cloud-agents/self-hosting/security-and-networking/) — Network egress and data boundaries. diff --git a/src/content/docs/agent-platform/cloud-agents/self-hosting/quickstart.mdx b/src/content/docs/agent-platform/cloud-agents/self-hosting/quickstart.mdx new file mode 100644 index 0000000..f4ea59d --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/self-hosting/quickstart.mdx @@ -0,0 +1,89 @@ +--- +title: Self-hosting quickstart +description: >- + Get a managed self-hosted Oz worker running on Docker and route your first + cloud agent run to it in under 10 minutes. +--- + +Run your first Oz cloud agent on your own infrastructure in ~10 minutes using the managed architecture with the Docker backend — the default and fastest path to self-hosting. + +:::note +This quickstart sets up the [managed architecture](/agent-platform/cloud-agents/self-hosting/#managed-architecture), where Oz orchestrates the agent and your worker provides the compute. **Prefer a CLI-only path with no Docker requirement?** Jump to the [Unmanaged quickstart](/agent-platform/cloud-agents/self-hosting/unmanaged/#unmanaged-quickstart) to run `oz agent run` directly on any host. +::: + +--- + +## Prerequisites + +* **Enterprise plan with self-hosting enabled** — [Contact sales](https://warp.dev/contact-sales) if self-hosting is not yet enabled for your team. +* **A Linux machine with Docker** — A VM, server, or local machine with the Docker daemon running Linux containers. Verify with `docker info`. Docker Desktop on macOS or Windows works for testing. +* **A team API key** — In the Warp app, go to **Settings** > **Cloud platform** > **Oz Cloud API Keys** to create a team-scoped API key. See [API Keys](/reference/cli/api-keys/) for details. +* **The Oz CLI** (for routing a test run) — See [Installing the CLI](/reference/cli/#installing-the-cli). + +--- + +## Run your first self-hosted agent + +_~10 minutes_ + +### 1. Export your API key + +Export the team API key so the worker container can authenticate to Oz automatically: + +```bash +export WARP_API_KEY="your_team_api_key" +``` + +### 2. Start the worker + +Run the `oz-agent-worker` container, mounting the host's Docker socket so the worker can spawn task containers. Choose any `--worker-id` meaningful for your team — you'll use this value to route tasks to this worker. + +```bash +docker run -v /var/run/docker.sock:/var/run/docker.sock \ + -e WARP_API_KEY="$WARP_API_KEY" \ + warpdotdev/oz-agent-worker --worker-id "my-worker" +``` + +**Expected outcome:** The worker connects to Oz and begins listening for tasks. You should see log output confirming the connection (something like `Connected to Oz` / `Waiting for tasks`). + +:::caution +For production deployments, pin to a specific image digest (e.g., `warpdotdev/oz-agent-worker@sha256:...`) instead of the `latest` tag. +::: + +### 3. Route a run to your worker + +In a separate terminal on any machine with the Oz CLI, route a cloud agent run to your worker by passing `--host` with the worker ID you chose: + +```bash +oz agent run-cloud --prompt "List the files in the current directory" --host "my-worker" +``` + +**Expected outcome:** Oz accepts the task, routes it to your worker, and the worker spawns a Docker container to execute the agent. You'll see the run appear in the [Oz dashboard](https://oz.warp.dev) with status moving from `QUEUED` → `INPROGRESS` → `SUCCEEDED`. + +### 4. Verify the run + +Open the [Oz dashboard](https://oz.warp.dev), find the new task, and confirm the session transcript shows the agent running against your worker. You can attach to the session at any time via [Agent Session Sharing](/agent-platform/local-agents/session-sharing/) to monitor or steer it. + +--- + +## Next steps + +* [Unmanaged quickstart](/agent-platform/cloud-agents/self-hosting/unmanaged/#unmanaged-quickstart) — ~5-minute CLI-only path: run `oz agent run` in your CI, Kubernetes pod, or dev box with no worker daemon and no Docker requirement. +* [Managed: Docker](/agent-platform/cloud-agents/self-hosting/managed-docker/) — Full Docker backend setup, including private registries, volume mounts, and runtime configuration. +* [Environments](/agent-platform/cloud-agents/environments/) — Define a repository, Docker image, and setup commands so agents have a reproducible workspace for every run. +* [Routing runs to self-hosted workers](/agent-platform/cloud-agents/self-hosting/#routing-runs-to-self-hosted-workers) — How to route tasks from schedules, integrations (Slack, Linear), the API, and the Oz web app. +* [Managed: Kubernetes](/agent-platform/cloud-agents/self-hosting/managed-kubernetes/) — Deploy workers into a Kubernetes cluster with Helm. +* [Self-hosted worker reference](/agent-platform/cloud-agents/self-hosting/reference/) — All CLI flags and config file options. + +## Troubleshooting + +**Worker won't start**\ +Verify Docker is running (`docker info`) and that the daemon platform is `linux/amd64` or `linux/arm64`. Musl-based (Alpine) worker hosts are not supported. + +**Worker won't connect**\ +Verify your API key has team scope. Ensure the machine has outbound internet access to `oz.warp.dev:443`. Increase log verbosity with `--log-level debug` to see connection details. + +**Task stays queued and never runs**\ +Confirm the `--host` value you passed to `oz agent run-cloud` matches your `--worker-id` exactly (case-sensitive). Check that the worker's team matches the team creating the task. + +For more, see [Troubleshooting](/agent-platform/cloud-agents/self-hosting/troubleshooting/). diff --git a/src/content/docs/agent-platform/cloud-agents/self-hosting/reference.mdx b/src/content/docs/agent-platform/cloud-agents/self-hosting/reference.mdx new file mode 100644 index 0000000..3764033 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/self-hosting/reference.mdx @@ -0,0 +1,206 @@ +--- +title: Self-hosted worker reference +description: >- + Complete reference for the oz-agent-worker daemon — CLI flags and config + file schema for the Docker, Kubernetes, and Direct backends. +--- + +Reference for the `oz-agent-worker` daemon: CLI flags and the full YAML config-file schema for all three [managed backends](/agent-platform/cloud-agents/self-hosting/#managed-architecture) — Docker, Kubernetes, and Direct. + +:::note +This page documents every flag and config option. For installation and backend-specific setup walkthroughs, see [Managed: Docker](/agent-platform/cloud-agents/self-hosting/managed-docker/), [Managed: Kubernetes](/agent-platform/cloud-agents/self-hosting/managed-kubernetes/), or [Managed: Direct](/agent-platform/cloud-agents/self-hosting/managed-direct/). This reference applies to the managed architecture only; the [unmanaged architecture](/agent-platform/cloud-agents/self-hosting/unmanaged/) uses `oz agent run` instead. +::: + +--- + +## Worker flags + +The following flags are available when starting the worker. + +### Required + +* `--worker-id` — A string identifying this worker. This is the value you pass to `--host` when routing tasks. Choose something meaningful for your team (e.g., `prod-runner-1` or `ci-worker`). Multiple workers can share the same ID for load balancing. +* `--api-key` or `WARP_API_KEY` env var — Your team API key for authentication. When running via Docker, pass it as `-e WARP_API_KEY="..."`. When running the binary directly, use `--api-key` or the environment variable. + +### Optional + +* `--config-file` — Path to a YAML [config file](#config-file). CLI flags take precedence over config file values. +* `--backend` — Backend type: `docker` (default), `kubernetes`, or `direct`. See [Managed: Kubernetes](/agent-platform/cloud-agents/self-hosting/managed-kubernetes/) and [Managed: Direct](/agent-platform/cloud-agents/self-hosting/managed-direct/) for backend-specific setup. +* `--log-level` — Log verbosity. One of `debug`, `info`, `warn`, `error`. Defaults to `info`. +* `--no-cleanup` — Keep task containers, Kubernetes Jobs, or workspace directories after execution instead of removing them. Useful for debugging failed tasks. +* `-v` / `--volumes` — Mount host directories into task containers (Docker backend only). Format: `HOST_PATH:CONTAINER_PATH` or `HOST_PATH:CONTAINER_PATH:MODE` (where MODE is `ro` or `rw`). Can be specified multiple times. +* `-e` / `--env` — Set environment variables for tasks. Format: `KEY=VALUE` (explicit value) or `KEY` (pass through from host environment). Can be specified multiple times. +* `--max-concurrent-tasks` — Maximum number of tasks to run concurrently. Defaults to `0` (unlimited). When set, additional tasks wait until a slot is available. +* `--idle-on-complete` — How long to keep the `oz` process alive after a task's conversation finishes, allowing follow-up interactions via session sharing. Uses duration format (e.g. `45m`, `10m`, `0s`). Defaults to `45m` when not set. Set to `0s` to disable. + +:::note +Worker IDs starting with `warp` are reserved and cannot be used. The worker refuses to start if `--worker-id` begins with `warp`. +::: + +### Example with all flags + +```bash +docker run -v /var/run/docker.sock:/var/run/docker.sock \ + -e WARP_API_KEY="$WARP_API_KEY" \ + warpdotdev/oz-agent-worker \ + --worker-id "prod-runner-1" \ + --log-level debug \ + --no-cleanup \ + --max-concurrent-tasks 4 \ + --idle-on-complete 10m \ + -v /opt/shared-cache:/cache:ro \ + -e NPM_TOKEN=your_token \ + -e GITHUB_TOKEN +``` + +:::caution +When running the worker via Docker, there are two levels of `-e` flags. Docker's `-e` passes env vars to the **worker container** (e.g., `WARP_API_KEY`). The worker's `-e` / `--env` flags pass env vars into the **task containers** the worker spawns. Keep these distinct. +::: + +--- + +## Config file + +For complex setups, use a YAML config file instead of (or in addition to) CLI flags. Pass it with `--config-file`: + +```bash +oz-agent-worker --api-key "$WARP_API_KEY" --config-file config.yaml +``` + +CLI flags always take precedence over config file values. + +### Docker backend config + +```yaml +worker_id: "my-worker" +cleanup: true +max_concurrent_tasks: 4 +idle_on_complete: "10m" +backend: + docker: + volumes: + - "/data:/data:ro" + - "/cache:/cache" + environment: + - name: NPM_TOKEN + value: "your_token" + - name: GITHUB_TOKEN # inherits from host environment +``` + +### Kubernetes backend config + +```yaml +worker_id: "k8s-worker" +max_concurrent_tasks: 4 +backend: + kubernetes: + namespace: "warp-oz" + default_image: "my-registry.io/dev-image:latest" + unschedulable_timeout: "2m" + pod_template: + nodeSelector: + kubernetes.io/os: linux + containers: + - name: task + resources: + requests: + cpu: "2" + memory: 4Gi + env: + - name: GITHUB_TOKEN + valueFrom: + secretKeyRef: + name: my-k8s-secret + key: github-token +``` + +### Direct backend config + +```yaml +worker_id: "direct-worker" +max_concurrent_tasks: 2 +backend: + direct: + workspace_root: "/var/lib/oz/workspaces" + oz_path: "/usr/local/bin/oz" + setup_command: "/opt/scripts/setup.sh" + teardown_command: "/opt/scripts/teardown.sh" + environment: + - name: MY_VAR + value: "hello" +``` + +### Config file fields + +**Top-level:** + +* `worker_id` — Worker identifier (same as `--worker-id` flag). +* `cleanup` — Whether to clean up after tasks. Defaults to `true`. Set to `false` to keep containers/workspaces for debugging (equivalent to `--no-cleanup`). +* `max_concurrent_tasks` — Maximum concurrent tasks. Defaults to unlimited. +* `idle_on_complete` — Duration to keep the `oz` process alive after task completion (e.g. `"45m"`, `"0s"`). +* `backend` — Backend configuration block. Only one backend (`docker`, `kubernetes`, or `direct`) may be specified. + +**`backend.docker`:** + +* `volumes` — List of volume mounts (same format as `-v` flag). +* `environment` — List of environment variables with `name` and optional `value`. If `value` is omitted, the variable is inherited from the host. + +**`backend.kubernetes`:** + +* `namespace` — Kubernetes namespace for task Jobs. Defaults to `default`. Selects the namespace inside the chosen cluster; does not choose the cluster. +* `kubeconfig` — Path to an explicit kubeconfig file. If omitted, the worker uses in-cluster config when running inside Kubernetes, or falls back to the default kubeconfig loading rules. +* `default_image` — Default Docker image for task Jobs when the run has no Warp environment image. Precedence: Warp environment image > `default_image` > `ubuntu:22.04`. Set this to skip creating a Warp environment when all your tasks use the same base image. +* `image_pull_policy` — One of `Always`, `Never`, or `IfNotPresent`. Defaults to `IfNotPresent`. +* `preflight_image` — Image used for the startup preflight Job. Defaults to `busybox:1.36`. Override this if your cluster only allows pulling from an internal or allowlisted registry. +* `setup_command` — Shell command to run before each task. +* `teardown_command` — Shell command to run after each task completes. +* `extra_labels` — Map of additional labels to add to task Jobs and Pods. +* `extra_annotations` — Map of additional annotations to add to task Jobs and Pods. +* `active_deadline_seconds` — Maximum lifetime for a task Job (Kubernetes `activeDeadlineSeconds`). +* `workspace_size_limit` — Size limit for the workspace `emptyDir` volume (e.g., `10Gi`). +* `unschedulable_timeout` — How long a pod may remain unschedulable before the task is failed early. Defaults to `30s`. Set to `0s` to disable the fail-fast behavior. +* `pod_template` — Raw Kubernetes PodSpec YAML merged with the worker's required fields at runtime. Use this to configure task pod scheduling, `serviceAccountName`, `imagePullSecrets`, `nodeSelector`, `tolerations`, resources, and environment variables (including `valueFrom.secretKeyRef` for Kubernetes Secrets). Define a container named `task` to customize the main task container directly; otherwise the worker appends its own. + +**`backend.direct`:** + +* `workspace_root` — Directory where per-task workspaces are created. Defaults to `/var/lib/oz/workspaces`. +* `oz_path` — Path to the oz CLI binary. If omitted, the worker looks up `oz` in `PATH`. +* `setup_command` — Shell command to run before each task. Receives `OZ_WORKSPACE_ROOT`, `OZ_RUN_ID`, `OZ_ENVIRONMENT_FILE`, and `OZ_WORKER_BACKEND` as environment variables. +* `teardown_command` — Shell command to run after each task completes. +* `environment` — List of environment variables (same format as the Docker backend). + +:::note +Only one backend can be configured at a time. Specifying more than one of `docker`, `kubernetes`, and `direct` in the same config file is an error. +::: + +--- + +## Metrics configuration + +The worker exports metrics over OpenTelemetry. Exporter selection is controlled by standard environment variables, not CLI flags or config file fields. Set these variables on the worker process (or the worker container via Docker `-e` / Kubernetes `env`). + +* `OTEL_METRICS_EXPORTER` — Exporter to use: `prometheus`, `otlp`, `console`, or `none`. When unset, defaults to `otlp`. +* `OTEL_EXPORTER_PROMETHEUS_HOST` — Bind address for the Prometheus exporter. Defaults to `localhost`. Set to `0.0.0.0` when running in Docker or Kubernetes. +* `OTEL_EXPORTER_PROMETHEUS_PORT` — Port for the Prometheus exporter. Defaults to `9464`. +* `OTEL_EXPORTER_OTLP_ENDPOINT` — OTLP collector endpoint (e.g., `http://otel-collector.observability.svc:4318`). +* `OTEL_EXPORTER_OTLP_PROTOCOL` — OTLP protocol: `http/protobuf` (default) or `grpc`. + +When deploying with the Helm chart, use the `metrics.*` values instead of setting these variables manually. See [Monitoring](/agent-platform/cloud-agents/self-hosting/monitoring/) for the full setup guide, metric catalog, Helm values, and sample PromQL queries. + +--- + +## Routing runs to self-hosted workers + +Once a worker is running, route cloud agent runs to it with the `--host` flag or its equivalents. See [Routing runs to self-hosted workers](/agent-platform/cloud-agents/self-hosting/#routing-runs-to-self-hosted-workers) for examples across the CLI, schedules, integrations, the API, and the web UI. + +--- + +## Related pages + +* [Managed: Docker](/agent-platform/cloud-agents/self-hosting/managed-docker/) — Docker backend setup, connectivity, and private registries. +* [Managed: Kubernetes](/agent-platform/cloud-agents/self-hosting/managed-kubernetes/) — Kubernetes backend setup, Helm chart, pod template, and operational notes. +* [Managed: Direct](/agent-platform/cloud-agents/self-hosting/managed-direct/) — Direct backend setup and workspace model. +* [Self-hosting overview](/agent-platform/cloud-agents/self-hosting/) — Architecture, decision guide, and Enterprise requirements. +* [Environments](/agent-platform/cloud-agents/environments/) — Define the Docker image, repos, and setup commands used by task containers. +* [Monitoring](/agent-platform/cloud-agents/self-hosting/monitoring/) — OpenTelemetry metrics for worker health, task throughput, and capacity. +* [Troubleshooting](/agent-platform/cloud-agents/self-hosting/troubleshooting/) — Worker and task failure diagnostics. diff --git a/src/content/docs/agent-platform/cloud-agents/self-hosting/security-and-networking.mdx b/src/content/docs/agent-platform/cloud-agents/self-hosting/security-and-networking.mdx new file mode 100644 index 0000000..6554ccb --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/self-hosting/security-and-networking.mdx @@ -0,0 +1,107 @@ +--- +title: Security and networking +description: >- + Security model, data boundaries, and network requirements for self-hosted Oz + cloud agents — including per-backend considerations and BYOLLM. +--- + +Self-hosting uses a split-plane architecture. Understanding which data stays on your infrastructure and which data routes through Warp is critical for security evaluation. This page summarizes the data model, network egress requirements, and backend-specific security considerations for self-hosted workers. + +:::note +This page applies to both the [managed](/agent-platform/cloud-agents/self-hosting/#managed-architecture) and [unmanaged](/agent-platform/cloud-agents/self-hosting/unmanaged/) architectures. Backend-specific notes call out Docker-, Kubernetes-, and Direct-only considerations. +::: + +## Data boundaries + +**Stored and executed only on your infrastructure:** + +* Repository clones and source files. +* Build artifacts and compiled outputs. +* Runtime secrets and environment variables. +* Container filesystem state (managed architecture) or host workspace (Direct backend / unmanaged). + +**Routes through Warp's backend** (under [Zero Data Retention (ZDR)](/enterprise/security-and-compliance/security-overview/#zero-data-retention-zdr)): + +* Orchestration metadata (task status, lifecycle events). +* Session transcripts, which include agent-generated summaries of code context, file contents the agent reads, and command output. +* LLM inference requests and responses, which include code context from the agent's interactions. + +:::note +While repositories are cloned and stored only on your infrastructure, code content appears in session transcripts and LLM prompts as part of normal agent operation. All data routed through Warp's backend is covered by [ZDR](/enterprise/security-and-compliance/security-overview/#zero-data-retention-zdr) agreements — Warp does not persistently store your source code or use it for model training. +::: + +--- + +## Network requirements + +Self-hosted Oz agents **do not require any network ingress**. They require outbound (egress) access to the following services: + +**Warp's backend (all architectures):** + +* `app.warp.dev` — port 443 +* `rtc.app.warp.dev` — port 443 +* `sessions.app.warp.dev` — port 443 +* `oz.warp.dev` — port 443 (managed architecture only) + +**Docker Hub** — for pulling task images (managed architecture only). + +**GitHub (`github.com`)** — only with the managed architecture, when using a Warp [environment](/agent-platform/cloud-agents/environments/) with configured GitHub repositories. + +**Linux distribution-specific package repositories** — only with the managed architecture, when using a Warp environment whose base image does not have Git pre-installed. The exact repositories depend on the package manager configuration in the environment's base image. + +:::note +All traffic uses HTTPS (port 443). No inbound ports need to be opened. +::: + +--- + +## Backend-specific security considerations + +### Docker backend + +* **Docker socket access** — The worker requires access to the Docker daemon to create task containers. When running the worker via Docker, this means mounting `/var/run/docker.sock`. Ensure appropriate access controls on the host. +* **Volume mounts** — If using `-v` / `--volumes`, be mindful of what host paths you expose to task containers. +* **Task isolation** — Each task runs in its own container. Containers are removed after execution by default (disable with `--no-cleanup` for debugging). + +### Kubernetes backend + +* **Kubernetes RBAC** — The worker needs namespaced permissions to create, get, list, watch, and delete Jobs and Pods. The Helm chart creates a minimal Role/RoleBinding scoped to a single namespace. The task namespace must allow creating Jobs with a root init container, as sidecar materialization currently depends on that pattern. Review your Pod Security Standards and admission policies accordingly. +* **Kubernetes service accounts** — The worker Deployment's ServiceAccount (used by the long-lived worker process) is separate from the optional task Job `serviceAccountName` you may configure in `pod_template`. Scope each appropriately. +* **API key management** — Store `WARP_API_KEY` in a Kubernetes Secret. Avoid hardcoding it in scripts or config files. If your organization uses an external secrets manager (HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, etc.), you can inject secrets into task pods via the CSI Secrets Store Driver or a similar operator — configure the required `volumes`, `volumeMounts`, and annotations in `pod_template`. +* **Task isolation** — Each task runs as a separate Kubernetes Job/Pod. Jobs are removed after execution by default (disable with `--no-cleanup` for debugging). + +### Direct backend + +* **Shared host kernel** — The Direct backend does not provide container-level isolation. Each task runs in an isolated workspace directory but shares the host OS and kernel. +* **Minimal environment by default** — The Direct backend intentionally starts tasks with a minimal environment (`HOME`, `TMPDIR`, `PATH` only). Sensitive worker credentials like `WARP_API_KEY` are not passed to tasks unless explicitly configured. +* **Workspace cleanup** — Workspaces under `workspace_root` are removed after execution by default (disable with `--no-cleanup` for debugging). + +### Unmanaged + +* **Host inheritance** — Agents inherit the host's network access, tools, and credentials. If the host has access to a VPN or internal services, the agent will too. Evaluate accordingly. +* **Kubernetes pod isolation** — Whether Kubernetes pods provide sufficient sandboxing for agents depends on your cluster configuration and risk profile. Evaluate your pod security policies, network policies, and RBAC settings based on your organization's security requirements. + +--- + +## VPN and on-premises access + +Since self-hosted agents run on your infrastructure, they inherit your network access. Self-hosted agents can reach services behind VPNs, self-hosted GitLab/Bitbucket instances, databases, and any other internal resources your host can reach. This is one of the primary reasons teams choose self-hosting. + +See [GitLab](/agent-platform/cloud-agents/integrations/gitlab/) and [Bitbucket](/agent-platform/cloud-agents/integrations/bitbucket/) setup guides for SCM integration details. + +--- + +## LLM inference and BYOLLM + +LLM inference routes through Warp's backend, which has [ZDR](/enterprise/security-and-compliance/security-overview/#zero-data-retention-zdr) agreements with all contracted model providers. Enterprise teams that need full control over inference routing can use [Bring Your Own LLM (BYOLLM)](/enterprise/enterprise-features/bring-your-own-llm/) to route inference through their own cloud provider accounts. + +BYOLLM currently applies to interactive (local) agents; cloud agent BYOLLM support is coming. + +--- + +## Related pages + +* [Self-hosting overview](/agent-platform/cloud-agents/self-hosting/) — Managed vs unmanaged and architecture decision guide. +* [Security overview](/enterprise/security-and-compliance/security-overview/) — Warp's broader security model, including ZDR. +* [Bring Your Own LLM (BYOLLM)](/enterprise/enterprise-features/bring-your-own-llm/) — Route inference through your own cloud provider accounts. +* [Self-hosted worker reference](/agent-platform/cloud-agents/self-hosting/reference/) — CLI flags and config schema, including every security-relevant option. diff --git a/src/content/docs/agent-platform/cloud-agents/self-hosting/troubleshooting.mdx b/src/content/docs/agent-platform/cloud-agents/self-hosting/troubleshooting.mdx new file mode 100644 index 0000000..b94c7be --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/self-hosting/troubleshooting.mdx @@ -0,0 +1,153 @@ +--- +title: Self-hosting troubleshooting +description: >- + Diagnose and fix common problems with self-hosted Oz worker daemons across + Docker, Kubernetes, and Direct backends. +--- + +Diagnostic guides for the `oz-agent-worker` daemon and its task execution. Use this page when a worker won't start, won't connect, tasks stay queued, or tasks fail. + +:::note +The steps below apply to the [managed architecture](/agent-platform/cloud-agents/self-hosting/#managed-architecture) (`oz-agent-worker` daemon). For [unmanaged](/agent-platform/cloud-agents/self-hosting/unmanaged/) deployments, refer to the documentation for the environment running `oz agent run` (e.g., GitHub Actions, Kubernetes). +::: + +--- + +## Worker won't start + +### Docker backend + +**Cause:** Docker isn't running, or the daemon platform isn't supported. + +**Fix:** + +1. Verify Docker is running: `docker info`. +2. Confirm the daemon platform is `linux/amd64` or `linux/arm64`. Windows containers are not supported. +3. If the worker runs inside Docker, confirm the `/var/run/docker.sock` mount is correct and the mounting user has permission to the socket. + +### Kubernetes backend + +**Cause:** The startup preflight Job failed. Common reasons include insufficient RBAC, restrictive Pod Security policies, or an unreachable Kubernetes API server. + +**Fix:** + +1. Check the worker logs for the preflight diagnostic message. +2. Confirm the worker's namespace has these permissions: `create`, `get`, `list`, `watch`, `delete` on `jobs`; `get`, `list`, `watch` on `pods`; `get` on `pods/log`; `list` on `events`. +3. Confirm the task namespace allows pods with a **root init container** (required for sidecar materialization). +4. If your cluster restricts image sources, set `preflight_image` in the worker config to an allowlisted image (default is `busybox:1.36`). +5. To pull the preflight image from a private registry, configure `imagePullSecrets` in `pod_template` — these secrets also apply to the preflight Job. + +### Direct backend + +**Cause:** The `oz` CLI isn't installed or isn't on the worker's `PATH`. + +**Fix:** + +1. Install the Oz CLI on the worker host. See [Installing the CLI](/reference/cli/#installing-the-cli). +2. If the CLI isn't on `PATH`, set `oz_path` in the config file to the absolute path of the `oz` binary. + +--- + +## Worker won't connect + +**Cause:** The API key is invalid, expired, or the host cannot reach Oz's backend. + +**Fix:** + +1. Confirm your API key is correct, not expired, and has team scope. +2. Regenerate the API key in **Settings** > **Cloud platform** > **Oz Cloud API Keys** if you suspect it's invalid. +3. Ensure the host has outbound internet access to `oz.warp.dev:443`. +4. Check that no firewall rules are blocking WebSocket connections to `wss://oz.warp.dev`. +5. Increase log verbosity with `--log-level debug` to see connection details. + +See [Security and networking](/agent-platform/cloud-agents/self-hosting/security-and-networking/#network-requirements) for the full list of outbound endpoints the worker needs. + +--- + +## Tasks not being picked up + +**Cause:** The worker isn't running, the `--host` value doesn't match the worker's `--worker-id`, or the worker and task belong to different teams. + +**Fix:** + +1. Confirm the worker is running and connected. Check the worker logs for `Listening for tasks` or similar. +2. Verify the `--host` (or `worker_host`) value you passed matches your `--worker-id` exactly. Case-sensitive. +3. Ensure the worker's team matches the team creating the task. + +--- + +## Metrics not appearing + +**Cause:** The worker is running but metrics aren't showing up in Prometheus or your collector. + +**Fix:** + +1. Verify `OTEL_METRICS_EXPORTER` is set correctly on the worker process. Run `curl -s localhost:9464/metrics` from the worker host (for `prometheus` mode) to confirm the endpoint is serving. +2. For Prometheus scrape mode, confirm the bind address is `0.0.0.0` (not `localhost`) when running in Docker or Kubernetes. `localhost` is only reachable from inside the container. +3. Confirm no firewall or network policy blocks the metrics port (default `9464`). +4. For OTLP push mode, verify `OTEL_EXPORTER_OTLP_ENDPOINT` points to a reachable collector and that the protocol matches (`http/protobuf` vs `grpc`). +5. When using the Helm chart, confirm `metrics.enabled=true` is set. Check that the `Service` and (optionally) `PodMonitor` were created: `kubectl get svc,podmonitor -n <namespace>`. +6. If using `metrics.podMonitor.create=true`, verify the `monitoring.coreos.com` CRDs are installed in the cluster. The `PodMonitor` resource requires the Prometheus Operator. +7. Restart the worker with `--log-level debug` and look for metrics-related error messages at startup. + +See [Monitoring](/agent-platform/cloud-agents/self-hosting/monitoring/) for the full setup guide. + +--- + +## Task failures + +**Cause:** A variety of reasons depending on backend. Start with the diagnostic steps common to all backends, then follow the backend-specific checks. + +**Fix (all backends):** + +1. Review task logs in the [Oz dashboard](https://oz.warp.dev) or via [session sharing](/agent-platform/local-agents/session-sharing/). +2. Use `--no-cleanup` to keep the container, Job, or workspace around for inspection after failure. +3. Use `--log-level debug` to see detailed execution logs. +4. Ensure the worker machine or cluster has sufficient resources (CPU, memory, disk). + +### Docker backend (task failures) + +1. Verify Docker is running (`docker info`). +2. If using a custom image, confirm it is **glibc-based** (not Alpine/musl) and that its architecture matches the worker's Docker daemon platform. + +### Kubernetes backend (task failures) + +1. Check task Job and Pod status: `kubectl get jobs,pods -n <namespace>`. +2. Common issues: + * **Unschedulable pods** — Check node selectors, tolerations, and resource requests in `pod_template`. + * **Image pull failures** — Check `imagePullSecrets` in `pod_template`. + * **Admission policy rejections** — Review Pod Security Standards, OPA Gatekeeper, Kyverno, or similar admission controllers. +3. The worker fails a task early if its pod remains unschedulable beyond `unschedulable_timeout` (default `30s`). Raise the timeout or fix the scheduling issue. + +### Direct backend (task failures) + +1. Verify the Oz CLI is accessible. +2. Verify the workspace root directory has write permissions for the user running the worker. + +--- + +## Image pull failures + +### Docker backend (image pull) + +1. If using a private registry, ensure Docker credentials are available to the worker. See [Private Docker registries](/agent-platform/cloud-agents/self-hosting/managed-docker/#private-docker-registries). +2. Try pulling the image manually on the worker host: `docker pull <image>`. + +### Kubernetes backend (image pull) + +1. Configure `imagePullSecrets` in the `pod_template` section of your worker config. +2. Verify the Secret exists in the task namespace and contains valid credentials. + +### Both backends (image pull) + +* Verify the image exists and the tag is correct. +* Check network connectivity from the worker/cluster to the registry. + +--- + +## Related pages + +* [Self-hosting overview](/agent-platform/cloud-agents/self-hosting/) — Architecture and decision guide. +* [Self-hosted worker reference](/agent-platform/cloud-agents/self-hosting/reference/) — CLI flags and config schema, including every flag mentioned here. +* [Security and networking](/agent-platform/cloud-agents/self-hosting/security-and-networking/) — Outbound endpoints the worker needs. +* [Agent Session Sharing](/agent-platform/local-agents/session-sharing/) — Attach to running tasks to debug interactively. diff --git a/src/content/docs/agent-platform/cloud-agents/self-hosting/unmanaged.mdx b/src/content/docs/agent-platform/cloud-agents/self-hosting/unmanaged.mdx new file mode 100644 index 0000000..e80a3d0 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/self-hosting/unmanaged.mdx @@ -0,0 +1,136 @@ +--- +title: Unmanaged architecture +description: >- + Run Oz agents in your existing CI, Kubernetes, or dev environments using the + oz agent run CLI. You orchestrate the runs; Warp provides tracking and + observability. +--- + +With the unmanaged architecture, **you orchestrate agent runs** by invoking `oz agent run` directly from your existing CI pipelines, Kubernetes pods, VMs, or dev boxes. The agent runs on whatever host the command is executed from; Warp tracks the session for you but does not start or stop agents. + +:::note +Unmanaged is the right choice if you already have a system that schedules work (CI, internal orchestrators, cron, dev environments). If you'd rather have Oz trigger and route runs from Slack, Linear, schedules, or the API, use the [managed architecture](/agent-platform/cloud-agents/self-hosting/#managed-architecture) instead. +::: + +## When to use unmanaged + +* **CI/CD pipelines** — Run agents as part of a build or deployment workflow. This is how the [`warpdotdev/oz-agent-action`](https://github.com/warpdotdev/oz-agent-action) GitHub Action works. +* **Kubernetes pods** — Run agents inside pods with access to your cluster's network and services. +* **Dev boxes and VMs** — Run agents in pre-provisioned development environments. Especially useful for large monorepos with long setup times. +* **Existing orchestrators** — Drop `oz agent run` into any system that schedules work (Jenkins, Buildkite, internal job schedulers). + +Unmanaged works on any platform Warp supports (Linux, macOS, Windows) with no dependency on Docker or any other sandboxing platform. + +--- + +## Unmanaged quickstart + +_~5 minutes_ + +No Docker, no worker daemon, no environment required — just the Oz CLI on any host that can reach the internet. + +### Prerequisites + +* **The Oz CLI** installed on the machine where agents will run. See [Installing the CLI](/reference/cli/#installing-the-cli) for platform-specific instructions. +* **A Warp API key** — For automation, create a team-scoped API key in the Warp app at **Settings** > **Cloud platform** > **Oz Cloud API Keys**. See [API Keys](/reference/cli/api-keys/) for details. + +### 1. Authenticate + +Export your API key so the CLI can authenticate requests automatically: + +```bash +export WARP_API_KEY="your_team_api_key" +``` + +### 2. Run an agent + +Invoke `oz agent run` in the directory where you want the agent to operate. The agent has access to whatever tools, network resources, and credentials the host provides. + +```bash +oz agent run --prompt "Refactor the authentication module" --share team +``` + +**Expected outcome:** The agent starts immediately in the current working directory, and a tracked session appears in the [Oz dashboard](https://oz.warp.dev). + +### 3. Control sharing + +Use `--share` to control who can attach to the session and steer the agent: + +* `--share` — Share the session with yourself (accessible on other devices or in a browser). +* `--share team` or `--share team:view` — Give all team members read-only access. +* `--share team:edit` — Give all team members read/write access. +* `--share user@example.com` — Give a specific user read-only access. +* `--share user@example.com:edit` — Give a specific user read/write access. + +The `--share` flag can be repeated to combine multiple sharing targets. If you authenticate with a team API key, agents are automatically team-scoped. + +--- + +## Example: GitHub Actions + +Warp maintains the [`warpdotdev/oz-agent-action`](https://github.com/warpdotdev/oz-agent-action) action for running agents in GitHub Actions. The action wraps `oz agent run` and is a drop-in for CI workflows: + +```yaml +- name: Run Oz agent + uses: warpdotdev/oz-agent-action@v1 # wraps `oz agent run` under the hood + with: + prompt: "Review the code changes on this branch" + warp_api_key: ${{ secrets.WARP_API_KEY }} +``` + +See [GitHub Actions integration](/agent-platform/cloud-agents/integrations/github-actions/) for full details. + +## Example: Kubernetes + +Run an agent inside a Kubernetes pod with access to your cluster's services: + +```yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: oz-agent-task +spec: + template: + spec: + containers: + - name: oz-agent + image: warpdotdev/warp-agent:latest + command: ["agent", "run", "--prompt", "Run the test suite and report failures"] + env: + - name: WARP_API_KEY + valueFrom: + secretKeyRef: + name: warp-credentials + key: api-key + restartPolicy: Never +``` + +:::caution +For production deployments, pin to a specific Docker image digest (e.g., `warpdotdev/warp-agent@sha256:...`) instead of `latest` to ensure reproducible builds. +::: + +:::note +Whether Kubernetes pods provide sufficient sandboxing for agents depends on your cluster configuration and risk profile. Evaluate your pod security policies, network policies, and RBAC settings based on your organization's security requirements. +::: + +--- + +## Tracking and observability + +Unmanaged agents are tracked on Warp's backend. Each run creates a persistent session that your team can: + +* **View** in the [Oz dashboard](https://oz.warp.dev). +* **Attach to** via [Agent Session Sharing](/agent-platform/local-agents/session-sharing/) to monitor or steer. +* **Query** through the [Oz API/SDK](/reference/api-and-sdk/) for custom dashboards or monitoring. + +Unmanaged sessions benefit from the same shared configuration as other cloud agent runs — [MCP servers](/agent-platform/cloud-agents/mcp/), [secrets](/agent-platform/cloud-agents/secrets/), Warp Drive context, and saved prompts all apply. + +--- + +## Related pages + +* [Self-hosting overview](/agent-platform/cloud-agents/self-hosting/) — Compare managed and unmanaged, plus the architecture decision guide. +* [GitHub Actions integration](/agent-platform/cloud-agents/integrations/github-actions/) — Run agents in CI with the official action. +* [Deployment patterns](/agent-platform/cloud-agents/deployment-patterns/) — Pattern 1 (CLI-only) explains the unmanaged model conceptually. +* [Oz CLI](/reference/cli/) — Full CLI reference for `oz agent run` and related commands. +* [Agent Session Sharing](/agent-platform/local-agents/session-sharing/) — Attach to running sessions to monitor or steer them. diff --git a/src/content/docs/agent-platform/cloud-agents/skills-as-agents.mdx b/src/content/docs/agent-platform/cloud-agents/skills-as-agents.mdx new file mode 100644 index 0000000..92ed7e5 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/skills-as-agents.mdx @@ -0,0 +1,147 @@ +--- +title: Skills as Agents +description: >- + Run agents based on skills for consistent, repeatable workflows. Use skills + with local or cloud agents from the CLI, Oz web app, API, or on a schedule. +--- + +You can start an agent from a [skill](/agent-platform/capabilities/skills/)—a reusable set of instructions that defines what the agent should do. When you run an agent based on a skill, the skill provides the base prompt and behavior, while you supply additional context for that specific run. + +Skills work with both **local agents** (running on your machine) and **cloud agents** (running in Warp's infrastructure). + +This is useful when you want: + +* **Consistent behavior** — The same skill produces the same workflow every time, regardless of who triggers it or where it runs. +* **Repeatable automation** — Run skills on schedules for maintenance tasks like code cleanup, dependency updates, or issue triage. +* **Shareable workflows** — Skills live in repositories, so your team can version, review, and collaborate on agent behavior. + +--- + +## How Skills become available + +Skill discovery depends on whether you're running a local or cloud agent. + +### Local agents + +For local agent runs (`oz agent run`), skills are automatically discovered from your current repository. Warp scans these directories in order of precedence: + +* **`.warp/skills/`** +* **`.agents/skills/`** +* **`.claude/skills/`** +* **`.codex/skills/`** +* **`.cursor/skills/`** +* **`.gemini/skills/`** +* **`.copilot/skills/`** +* **`.factory/skills/`** +* **`.github/skills/`** +* **`.opencode/skills/`** + +You can also specify a skill from any accessible repository using the fully qualified format: `owner/repo:skill-name`. + +### Cloud agents + +For cloud agent runs (`oz agent run-cloud`), skills are discovered from repositories configured in your [environments](/agent-platform/cloud-agents/environments/). + +**Discovery workflow:** + +1. **Create a skill** in your repository (see [Creating skills](/agent-platform/capabilities/skills/#creating-skills)) +2. **Add the repository** to an environment +3. **The skill appears** in the Agents list in the Oz web app + +:::note +You can also list available skills programmatically using the `GET /agent` endpoint. See the [Oz API](/reference/api-and-sdk/) reference for details. +::: + +--- + +## Running skill-based agents + +You can start an agent from a skill using multiple entry points. + +### Oz web app + +The [Oz web app](/agent-platform/cloud-agents/oz-web-app/) at [oz.warp.dev](https://oz.warp.dev) provides a visual interface for running skill-based agents. From the web app, you can: + +* Browse all skills available from your environments on the **Agents** page +* View suggested agents from Warp's public [oz-skills repository](https://github.com/warpdotdev/oz-skills) +* Start a new run by selecting a skill, environment, and prompt +* Create scheduled agents that run skills on a cron schedule + +For a complete walkthrough of the web app interface, see [Oz Web App](/agent-platform/cloud-agents/oz-web-app/). + +### CLI + +Use the `--skill` flag with the Oz CLI: + +```sh +# Run locally with a skill +oz agent run --skill "owner/repo:skill-name" --prompt "additional context" + +# Run in the cloud with a skill +oz agent run-cloud \ + --environment <ENV_ID> \ + --skill "owner/repo:skill-name" \ + --prompt "additional context" +``` + +For full CLI documentation, see [Using skills](/reference/cli/#using-skills) in the CLI reference. + +### API & SDK + +Use the `skill_spec` parameter when creating a run: + +```json +{ + "prompt": "additional context for this run", + "config": { + "environment_id": "<ENV_ID>", + "skill_spec": "owner/repo:skill-name" + } +} +``` + +For full API documentation, see [Agent configuration](/reference/api-and-sdk/#agent-configuration) in the API reference. + +--- + +## Running skills on a schedule + +One of the most powerful uses for skill-based agents is running them on a schedule. [Scheduled agents](/agent-platform/cloud-agents/triggers/scheduled-agents/) execute automatically at specified times, making them ideal for: + +* **Dead code cleanup** — Weekly scans for unused code or stale feature flags +* **Dependency updates** — Daily or weekly checks for security updates +* **Issue triage** — Regular categorization and prioritization of open issues +* **Documentation refresh** — Periodic updates to keep docs in sync with code + +**Creating a scheduled skill-based agent:** + +```sh +oz schedule create \ + --name "Weekly Code Cleanup" \ + --cron "0 10 * * 1" \ + --environment <ENV_ID> \ + --prompt "Scan for dead code and unused feature flags. Open a PR with removals." +``` + +You can also create schedules from the [Oz web app](/agent-platform/cloud-agents/oz-web-app/) using the **New schedule** action. + +For full scheduling documentation, see [Scheduled Agents](/agent-platform/cloud-agents/triggers/scheduled-agents/). + +--- + +## Suggested Skills + +The [Oz web app](/agent-platform/cloud-agents/oz-web-app/) displays suggested agents from the public [warpdotdev/oz-skills](https://github.com/warpdotdev/oz-skills) repository. These are pre-built skills that demonstrate common use cases and can be used as starting points for your own workflows. + +Suggested skills appear on the Agents page under the **Suggested** filter. + +--- + +## Related resources + +* [Skills](/agent-platform/capabilities/skills/) — How to create skills and skill file format +* [Environments](/agent-platform/cloud-agents/environments/) — Configure repositories and runtime context for cloud agents +* [Scheduled Agents](/agent-platform/cloud-agents/triggers/scheduled-agents/) — Run agents automatically on a cron schedule +* [Oz Web App](/agent-platform/cloud-agents/oz-web-app/) — Visual interface for managing cloud agents +* [Oz CLI](/reference/cli/) — Command-line interface for running agents +* [Oz API & SDK](/reference/api-and-sdk/) — Programmatic access to cloud agents diff --git a/src/content/docs/agent-platform/cloud-agents/team-access-billing-and-identity.mdx b/src/content/docs/agent-platform/cloud-agents/team-access-billing-and-identity.mdx new file mode 100644 index 0000000..97f2d52 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/team-access-billing-and-identity.mdx @@ -0,0 +1,234 @@ +--- +title: Access, billing, and identity permissions +description: >- + Understand how access to cloud agents works for individuals and teams, how + billing and credits apply, and how Warp maps user identities across + integrations. +--- + +This page explains how access to cloud agents works for both individual users and teams, how billing and credits apply, and how Warp maps user identities across integrations. + +--- + +## Overview: individual vs team access + +Cloud agents can be used in two ways: + +**Individual users** (without a team): +* Can run cloud agents via CLI or API +* Can use normal Warp credits, [Cloud Agent Credits](/support-and-community/plans-and-billing/credits/#cloud-agent-credits), or a Build plan with available credits +* Agents run on Warp-hosted infrastructure +* Cannot use integrations (Slack, Linear) or self-hosted agents + +**Teams** (users who are part of a [Warp team](/knowledge-and-collaboration/teams/)): +* All individual capabilities, plus: +* Can use integrations (Slack, Linear) to trigger agents +* Can self-host agents on their own infrastructure (Enterprise only) +* Share team-level configuration (environments, secrets, integrations) +* Team must be on Build, Max, or Business plan with at least 20 credits (any type) for cloud agents and integrations + +--- + +## Individual access + +Individual users can run cloud agents via the CLI or API without being part of a team. + +**How it works:** + +* Run agents using `oz agent run-cloud` or the Oz API +* Credits are drawn from your normal Warp credits, Cloud Agent Credits (if available), or Build plan credits +* Agents execute on Warp-hosted infrastructure + +**What you can do:** + +* Run cloud agents from CI/CD pipelines +* Trigger agents programmatically via API +* Use personal secrets for authentication + +**What requires a team:** + +* Integrations (Slack, Linear) +* Self-hosted agent execution +* Team secrets and shared configuration + +--- + +## Team access + +A [Warp team](/knowledge-and-collaboration/teams/) is a group of users who share configuration and collaborate on cloud agents. Teams can be created on any plan, including Free. + +**What teams enable:** + +* **Integrations** - Create Slack and Linear integrations that all team members can use +* **Shared configuration** - Team-level environments, secrets, and settings +* **Self-hosting** - Run agents on your own infrastructure (Enterprise only) +* **Team visibility** - Shared observability into agent runs and history + +Integrations are created at the team level, not per-user. Once a Slack or Linear integration is installed, everyone on your Warp team can use **@Oz** in the connected workspace. The integration behaves the same way for all teammates, and everyone shares the same underlying environment configuration. + +When someone triggers a cloud agent for the first time, Warp may prompt them to grant GitHub authorization so the agent can open pull requests or push branches under their identity. This allows each run to use the correct permissions without requiring additional setup from an admin. + +#### Requirements for integrations + +Integrations and [cloud agents](/agent-platform/cloud-agents/overview/) run inside Warp's cloud, which means usage is billed based on [credits](/support-and-community/plans-and-billing/credits/). + +Your team must meet the following requirements to run integrations: + +* You must be on a plan that supports **[Reload Credits (Add-on Credits)](/support-and-community/plans-and-billing/add-on-credits/)**. + * Supported: **Build, Max, Business** + * Not supported: Pro, Turbo, Lightspeed, legacy Business. +* Your team needs at least **20 credits** available to run cloud agents and integrations (any type of Warp credits work) + +When a user triggers an agent through an integration (like Slack or Linear), the run draws from credits in a specific order. It starts with any [Cloud Agent Credits](/support-and-community/plans-and-billing/credits/#cloud-agent-credits) the user has, then moves to the user's base credits, followed by the team's Reload Credits, and finally the user's own Reload Credits. Enterprises may have different payment options and credit plans that affect this flow. If all applicable credit sources are exhausted, integrations and cloud agents will not work until credits are added. + +:::note +If you're on an Enterprise plan, please reach out to [warp.dev/contact-sales](https://warp.dev/contact-sales) with any billing questions related to integrations. +::: + +### Identity mapping + +Warp needs a reliable way to know which person a cloud agent run is acting for, across Warp, Slack, Linear, and GitHub. + +* Slack uses a dedicated account-linking flow to map a Slack user to their Warp account. This is the recommended path for Slack-triggered agents, since it doesn’t rely on email matching. +* Linear currently maps identities using email address matching. Your Linear email must match your Warp account email for Warp to correctly attribute and scope agent runs. +* Each teammate must authorize GitHub before an agent can write PRs or push branches on their behalf +* Agents always operate using the GitHub permissions of the triggering user + +This ensures runs are scoped to what the user is allowed to see and modify, and that ownership of PRs remains clear across teams and repositories. + +--- + +## Team GitHub authorization + +By default, Oz cloud agents authenticate with GitHub using the personal token of the user who triggered the run. Team GitHub authorization gives you an alternative: authenticate with the **Oz by Warp** GitHub App instead, so agents can clone repositories and open pull requests without relying on any individual's token. + +This is useful for fully automated workflows that use a [team API key](/reference/cli/api-keys/), like CI/CD pipelines, scheduled agents, and SDK-triggered runs, where you want code changes attributed to the GitHub App rather than a specific person. + +### How it works + +When an Oz agent task is initiated with a team API key, there is no individual user to authenticate on behalf of. Instead, Warp uses tokens issued by the **Oz by Warp** GitHub App installation to authenticate directly with GitHub. + +The GitHub App token gives the agent access to the repositories included in the app installation — it can clone repos, create branches, push commits, and open pull requests. During installation, you choose whether the app can access **all repositories** or only **selected repositories** in your GitHub organization, and this controls what team API key runs can access. + +### Setting up team GitHub authorization + +1. **Install the Oz by Warp GitHub App.** A user with admin permissions on the GitHub organization installs the [Oz by Warp](https://github.com/apps/oz-by-warp) GitHub App. During installation, grant the app access to **all repositories** or **selected repositories** in your org. + + :::note +There are two places you may encounter this installation flow: + * During the first-time experience for Oz, when you connect your GitHub account. + * When you click **Configure access on GitHub** in the repository selector while creating an environment. + + Each installation is scoped to a single GitHub organization or personal account — you can install the app to multiple orgs separately. +::: + + ![Oz by Warp GitHub App installation page showing repository access options](../../../../assets/agent-platform/oz-github-app-installation.png) + +2. **Enable the GitHub org for your Warp team.** A Warp team admin opens the Admin Panel in the Warp app (**Settings** > **Admin Panel** > **Platform**) and adds the GitHub organization under **Enabled GitHub Orgs**. This associates the GitHub App installation with your Warp team. + + ![Enabled GitHub Orgs setting in the Admin Panel Platform section](../../../../assets/agent-platform/admin-panel-enabled-github-orgs.png) + +3. **Use a team API key.** Tasks initiated with a team API key now use tokens from the GitHub App installation to clone repos and push changes. No individual GitHub authorization is needed. + +### How this relates to environments + +An [environment](/agent-platform/cloud-agents/environments/) is a template for an Oz cloud agent's sandbox — it defines the Docker image, repos, and setup commands, but it does not carry its own GitHub permissions. The same environment can be used by different users or by team API key runs, and each will authenticate to GitHub independently. + +The environment configuration and the **Enabled GitHub Orgs** setting in the Admin Panel serve different purposes: + +* **Environment repo list** - "This agent needs repos A, B, and C." +* **Enabled GitHub Orgs** - "This team can use the Oz by Warp GitHub App to access repos in this GitHub organization." + +### Personal tokens vs. GitHub App tokens + +Team GitHub authorization is complementary to the existing personal token flow: + +* **User-triggered runs** (personal API key, Slack, Linear, Warp app) - The agent authenticates as Oz acting on the triggering user's behalf. PRs and commits are attributed to that user. +* **Team API key runs with GitHub App authorization** - The agent authenticates as the GitHub App installation. PRs and commits are not attributed to any individual user. + +Both flows can coexist on the same team. Personal tokens are still used for user-triggered runs, and the GitHub App installation token is used when a task is initiated with a team API key. + +:::caution +GitHub App installation tokens are scoped to a single GitHub organization at a time. If your team works across repos in multiple GitHub organizations, the agent can only use the installation token for the organization enabled in the Admin Panel. Repos in other organizations require user-triggered runs with a personal API key. +::: + +:::note +To change which repositories the GitHub App can access, edit the app installation in your [GitHub settings](https://github.com/settings/installations). +::: + +--- + +## Data and permissions + +#### Slack / Linear + +Installing the Oz app gives Warp access to the Slack channels or Linear teams where the app is installed. + +**When a run is triggered, Warp receives:** + +* The content of the tagged thread or issue +* Relevant surrounding context used to build the agent prompt + +Warp stores only the content required for the agent to complete its task. You can message @Oz directly, mention it in channels, or tag it on specific issues depending on the integration. + +#### GitHub + +Warp’s behavior in GitHub is defined by two layers of control: + +1. **The Warp GitHub App installation scope** + * Determines which organizations and repositories Warp can read and write to + * Can be edited at any time in GitHub settings +2. **Permissions of the triggering user** + * Agents inherit the user’s read/write privileges + * Agents cannot elevate permissions, see additional repos, or write to repos the user cannot access + +**In practice, agents can only operate on repositories that:** + +* Are included in the environment configuration +* Are accessible to both the GitHub app and the triggering user + +--- + +## Additional notes: how cloud agents use credits + +Cloud agents can run automatically in the background when activated by a trigger such as a Slack mention, a Linear update, or a scheduled task. These runs require compute and model usage, which translates to credit consumption. + +**Typical credit usage:** + +Cloud agent runs consume credits based on the complexity of the task and whether an environment is used. The exact amount varies by run. + +#### How credit usage works + +How credits are consumed depends on how the agent run is triggered and authenticated: + +**User-triggered runs** (CLI with personal API key, Slack, Linear, or the Warp app): + +* Runs are tied to the triggering user's identity +* Credits are consumed starting with any credit grants specifically allocated for cloud agent usage, then the user's base credits, followed by the team's Reload Credits, and finally the user's own Reload Credits + +**Team API key runs** (fully automated or headless workflows): + +* Runs are not tied to any individual user +* Only the team's Reload Credit pool is used—no individual base credits are available +* Ideal for CI/CD pipelines, scheduled tasks, and other automated workflows +* For workflows that require code changes (opening pull requests, pushing branches, or writing to a repository), configure [team GitHub authorization](#team-github-authorization) so the agent can authenticate with the Oz by Warp GitHub App. Alternatively, use a [personal API key](/reference/cli/api-keys/) to authenticate as an individual user. + +For more details on creating and using API keys, see [API Keys](/reference/cli/api-keys/). + +:::note +When a user triggers an agent via Slack or Linear, the run follows the standard credit precedence, starting with any credit grants specifically allocated for cloud agent usage. This applies even for integrations—as long as the triggering user's identity can be mapped to their Warp account. +::: + +#### Who configures triggers and workflows + +All triggers and instructions used by cloud agents are defined and controlled by your team’s authorized users. + +* Admins or other authorized users decide which triggers exist, when they fire, and what the agent should do in response. +* Trigger behavior and the agent’s instructions (system prompts, workflow steps, repo access, etc.) are fully managed by your admins or other designated users. + +#### Staying aware of usage + +Because triggers and instructions are configured by your team, any credits used when an agent runs are billed to your team's Reload Credit balance. + +* It’s the team’s responsibility to manage triggers, confirm they behave as intended, and monitor usage. +* Reviewing triggers, prompts, and agent behavior periodically helps ensure that credit usage aligns with expectations. diff --git a/src/content/docs/agent-platform/cloud-agents/triggers/index.mdx b/src/content/docs/agent-platform/cloud-agents/triggers/index.mdx new file mode 100644 index 0000000..6f60e85 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/triggers/index.mdx @@ -0,0 +1,17 @@ +--- +title: Triggers +description: >- + Configure triggers to run cloud agents automatically based on schedules or + events. +--- + +Triggers allow you to run cloud agents automatically without manual intervention. You can set up agents to run on schedules, in response to webhooks, or through other automation patterns. + +To set up your first recurring agent, follow the [Scheduled Agents Quickstart](/agent-platform/cloud-agents/triggers/scheduled-agents-quickstart/). + +## Available trigger types + +* **[Scheduled Agents](/agent-platform/cloud-agents/triggers/scheduled-agents/)** - Run agents on a recurring schedule using cron expressions. +* **[CLI](/reference/cli/)** - Trigger cloud agents directly from your terminal using the Oz CLI. +* **[API & SDK](/reference/api-and-sdk/)** - Programmatically trigger agents via the Warp API or SDK. +* **[Integrations](/agent-platform/cloud-agents/integrations/)** - Trigger agents from external services like Slack, Linear, or GitHub Actions. diff --git a/src/content/docs/agent-platform/cloud-agents/triggers/scheduled-agents-quickstart.mdx b/src/content/docs/agent-platform/cloud-agents/triggers/scheduled-agents-quickstart.mdx new file mode 100644 index 0000000..dd96def --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/triggers/scheduled-agents-quickstart.mdx @@ -0,0 +1,57 @@ +--- +title: Scheduled Agents quickstart +description: >- + Schedule an Oz cloud agent to run recurring tasks automatically — issue + triage, dependency checks, code cleanup, and more. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Scheduled agents are Oz cloud agents that run on a recurring cron schedule, handling recurring tasks automatically without manual triggers. This guide walks you through setting up an agent that triages your GitHub bug reports every week, checks whether each issue has enough detail to investigate, and posts follow-up comments when information is missing. You'll use a prebundled skill and the Oz web app; no CLI or custom code required. + +Watch this short demo of creating and testing a scheduled agent: +<VideoEmbed url="https://youtu.be/M-zyyrGt2ug" /> + +--- + +## Prerequisites + +* **A Warp account on an eligible plan** - Build, Max, or Business, with credits available. See [Access, Billing, and Identity](/agent-platform/cloud-agents/team-access-billing-and-identity/). +* **An Oz cloud environment** - Agents run inside a configured environment that includes repos and other dependencies. If you don't have one, follow the [Cloud Agents Quickstart](/agent-platform/cloud-agents/quickstart/) to create one first. + +--- + +## 1. Set up a scheduled agent + +1. From the [Schedules page](https://oz.warp.dev/schedules) in the Oz web app, click **New schedule**. +2. Enter a name, e.g. `Weekly bug report triage`. +3. Under **Agent**, select **github-bug-report-triage** from the suggested skills. +4. Choose your environment. +5. Under **Frequency**, choose a preset or enter a custom cron expression (e.g., `0 9 * * 1` for every Monday at 9 AM). +6. Click **Create schedule**. + +**Breaking it down:** The schedule lives in Oz's cloud infrastructure. Unlike a local cron job, it fires even when your machine is off. Each run starts a fresh, isolated session with no state carried over from previous executions, and every run is tracked and auditable in the [Oz web app](/agent-platform/cloud-agents/oz-web-app/). + +--- + +## 2. Watch your first run + +To verify your setup without waiting for the schedule to fire, trigger a test run now: + +1. From the [Schedules page](https://oz.warp.dev/schedules) in the Oz web app, click the schedule you just created. +2. Click ⋮ and select **Run now**, then click **Run** to confirm. + +Your test run will appear under **All** on the [Runs page](https://oz.warp.dev/runs). Once the schedule fires on its cron, those runs will appear under **Recurring**. + +Runs are also accessible from the conversation panel view in the Warp app and on mobile via the Oz web app. + +:::note +**Prefer the CLI?** See [Scheduled Agents](/agent-platform/cloud-agents/triggers/scheduled-agents/) for `oz schedule create`, `oz schedule list`, and full schedule management commands. To use a custom skill instead of a prebundled one, see [Skills as Agents](/agent-platform/cloud-agents/skills-as-agents/). +::: + +--- + +## Next steps + +* **Trigger agents from your tools** - Connect Oz to Slack or Linear to trigger agents from mentions or issue updates. See [Integrations Quickstart](/agent-platform/cloud-agents/integrations/quickstart/). +* **Manage and refine your schedule** - Change the frequency, swap skills, or pause and resume the schedule. See [Scheduled Agents](/agent-platform/cloud-agents/triggers/scheduled-agents/) for the full reference. +* **Share with your team** - Schedules and environments are shared across your Warp team, so everyone benefits automatically. diff --git a/src/content/docs/agent-platform/cloud-agents/triggers/scheduled-agents.mdx b/src/content/docs/agent-platform/cloud-agents/triggers/scheduled-agents.mdx new file mode 100644 index 0000000..6fc9a56 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/triggers/scheduled-agents.mdx @@ -0,0 +1,301 @@ +--- +title: Scheduled Agents +description: >- + Run cloud agents on a cron schedule for automated maintenance and recurring + tasks. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Warp's Scheduled Agents let you run cloud agents automatically on a **recurring schedule**. They are designed for routine, repeatable tasks that should happen without manual intervention, such as dead code cleanup, dependency maintenance, issue triage, or periodic refactors. + +<VideoEmbed url="https://www.youtube.com/watch?feature=youtu.be&v=wX9cDbsRXHs" /> + +Scheduled Agents run in the background on Warp’s infrastructure. Each run starts from a clean session, executes a fixed prompt, and produces its own task and session history that can be inspected after the fact. + +--- + +### What are Scheduled Agents? + +A Scheduled Agent is a [cloud agent](/agent-platform/cloud-agents/overview/) that runs on a cron-based schedule. + +**Key characteristics:** + +* Runs automatically based on a cron expression. +* Uses a fixed prompt defined at schedule creation time. +* Starts a fresh agent session for every run. +* Executes in a specific Warp Environment, if provided. +* Consumes credits when it runs. +* Can be paused, updated, or deleted at any time. + +Scheduled Agents are ideal for work that should happen regularly and predictably, without needing a human to trigger the agent manually. + +### Common use cases + +Scheduled Agents are best suited for maintenance-style workflows, including skills that automate recurring tasks. For more on running skill-based agents on schedules, see [Skills as Agents](/agent-platform/cloud-agents/skills-as-agents/). + +Common use cases include: + +* Dead code or unused feature flag cleanup. +* Dependency updates or security scans. +* Issue or PR triage on a recurring cadence. +* Periodic documentation refreshes. +* Repository hygiene tasks like formatting or lint checks. +* Scheduled reporting or audits. + +Because each run is isolated, Scheduled Agents are safe to use for tasks that benefit from a clean, repeatable execution environment. + +--- + +### Scheduling agents with the Oz CLI + +Oz scheduled agents are managed through the Oz `schedule` family of CLI commands. + +All scheduling operations require the Oz CLI and an authenticated session + +#### Creating a schedule + +Use `oz schedule create` (with required flags) to define a new Scheduled Agent. + +**Each schedule requires:** + +* A name, for identification. +* A cron schedule. +* A prompt or skill that the agent will execute. +* An optional environment in which the agent will run. +* An optional [model selection](/reference/cli/#using-agent-profiles). +* [Optional MCP server configuration](/agent-platform/cloud-agents/mcp/). + +```bash +oz schedule create \ + --name=NAME \ + --cron=SCHEDULE \ + --prompt=PROMPT \ + [--environment=ENVIRONMENT_ID] \ + [--skill=SPEC] \ + [--host=WORKER_ID] \ + [--mcp=SPEC] \ + [--model=MODEL_ID] \ + [--file=PATH] +``` + +**Optional flags:** + +* `--skill <SPEC>` — use a skill as the base prompt (format: `repo:skill_name` or `org/repo:skill_name`). See [Skills as Agents](/agent-platform/cloud-agents/skills-as-agents/). +* `--host <WORKER_ID>` — run on a specific self-hosted worker instead of Warp-hosted infrastructure. +* `--mcp <SPEC>` — attach MCP servers (inline JSON, file path, or UUID). Can be repeated. +* `--model <MODEL_ID>` — override the default model. +* `--file <PATH>` — load schedule configuration from a YAML or JSON file. + +:::note +Environments are optional — if you don't specify one, the scheduled agent runs in a barebones sandbox. Without an environment, the agent won't have access to your code repositories, pre-installed tools, or setup commands, so this is only suited for tasks that don't need your codebase. +::: + +**Example** + +The following command schedules an agent to clean up old feature flags every four days: + +```bash +oz schedule create \ + --name "Feature Flag Cleanup" \ + --cron "0 10 */4 * *" \ + --prompt "Scan the repository for stale feature flags and remove any that are no longer referenced. Open a PR with the changes and include a summary." \ + --environment "KB1ndNMQAs5kjPdX2jatA8" +``` + +Once created, the agent will automatically run at the specified times without further action. + +Scheduled Agents support the same [model selection](/reference/cli/) and [MCP server configuration](/agent-platform/cloud-agents/mcp/) as other cloud agent triggers. + +#### Cron schedule format + +Warp uses standard cron syntax to define schedules. + +A cron expression consists of five fields: + +``` +minute hour day-of-month month day-of-week +``` + +For example: + +* `0 10 * * *` runs every day at 10:00 AM. +* `0 10 */4 * *` runs every four days at 10:00 AM. +* `0 8 1 * *` runs at 8:00 AM on the first day of every month. + +Make sure your cron expression reflects the cadence you want, as Scheduled Agents will run exactly according to this schedule. + +### Listing Scheduled Agents + +To view all Scheduled Agents for your team, use: + +```bash +oz schedule list +``` + +This command prints a table with details about each schedule, including: + +* Schedule ID +* Name +* Cron schedule +* Paused +* Last run time +* Next scheduled run +* Scope + +| ID | Name | Schedule | Paused | Last Ran | Next Run | Scope | +| ------ | -------------------- | --------------- | ------ | -------------------------------------------- | --------------------- | ----- | +| abc123 | Feature Flag Cleanup | `0 10 */4 * *` | No | `2025-11-24 10:00 AM<task id><session link>` | `2025-11-28 10:00 AM` | Team | +| def456 | Issue Triage | `0 8 1 * *` | Yes | `2025-11-24 08:00 AM<task id><session link>` | Paused | - | + +Each completed run also includes links to: + +* The task created by the agent. +* The full agent session, including logs and outputs. + +This makes it easy to audit what ran, when it ran, and what the agent did. + +#### Viewing a specific Scheduled Agent + +Use `oz schedule get` to view detailed information about a single Scheduled Agent. + +```bash +oz schedule get SCHEDULE_ID +``` + +This command returns additional details not shown in the list view, including: + +* Full schedule configuration +* Prompt and model configuration +* Environment and MCP settings +* Recent runs and execution metadata +* Links to related tasks and agent sessions + +This is useful when auditing behavior, debugging failures, or reviewing how a Scheduled Agent is configured. + +### Pausing and unpausing schedules + +Scheduled Agents can be temporarily disabled without deleting them. + +```bash +oz schedule pause SCHEDULE_ID +``` + +When paused, the agent will not run at its scheduled times. + +**Example** + +```bash +oz schedule pause abc123 +``` + +#### Unpausing a schedule + +```bash +oz schedule unpause SCHEDULE_ID +``` + +Once unpaused, the agent resumes running according to its original cron schedule. + +### Editing Scheduled Agents + +You can modify an existing schedule using `oz schedule update`. + +You may update one or more properties at a time, including: + +* The schedule name. +* The cron schedule. +* The prompt used for future runs. +* The skill used as the base prompt. +* The environment used for execution. +* The model, MCP, and host configuration used for future runs. + +#### Command + +```bash +oz schedule update SCHEDULE_ID \ + [--name=NAME] \ + [--cron=SCHEDULE] \ + [--prompt=PROMPT] \ + [--environment=ENVIRONMENT_ID] \ + [--skill=SPEC] \ + [--remove-skill] \ + [--host=WORKER_ID] \ + [--mcp=SPEC] \ + [--remove-mcp=SERVER_NAME] \ + [--model=MODEL_ID] +``` + +**Additional update flags:** + +* `--skill <SPEC>` — update the skill used as the base prompt. +* `--remove-skill` — remove the skill from this scheduled agent. +* `--host <WORKER_ID>` — update the execution host. +* `--mcp <SPEC>` — add MCP servers to this schedule. +* `--remove-mcp <SERVER_NAME>` — remove an MCP server by name. +* `--remove-environment` — remove the environment from this schedule. + +#### Examples + +Change when a scheduled agent runs, leaving everything else unchanged: + +```bash +oz schedule update abc123 --cron "0 9 */4 * *" +``` + +Update the environment used for future runs: + +```bash +oz schedule update abc123 --environment=jkl789 +``` + +Changes apply only to future runs. Past runs and their session history remain unchanged. + +### Deleting a Scheduled Agent + +To permanently remove a schedule, use: + +```bash +oz schedule delete SCHEDULE_ID +``` + +**Example** + +```bash +oz schedule delete abc123 +``` + +Deleting a schedule immediately stops all future runs. Previous runs and their session history remain accessible for auditing and review. + +--- + +### Execution model and behavior + +Each scheduled run behaves like a standard cloud agent run, with a few important guarantees: + +* Every run starts a fresh session. +* No state is carried over between runs unless your environment explicitly persists data. +* Runs execute automatically without human intervention. +* All usage is billed to the team’s shared credit balance. + +If a scheduled run fails, it does not block future runs. Each execution is independent. + +### Permissions and responsibility + +Scheduled Agents are created and managed by authorized users on a Warp team. + +By creating a Scheduled Agent, you are responsible for: + +* The cron schedule and how often the agent runs. +* The instructions provided in the prompt. +* The environment and integrations the agent has access to. +* The credits consumed by scheduled executions. + +Carefully review prompts and schedules before deploying them broadly, especially for agents that can modify production code or infrastructure. + +### When to use Scheduled Agents vs triggers + +Scheduled Agents are best when work should happen on a predictable cadence. + +If you want an agent to run in response to an event, such as a Slack mention, PR update, or issue change, use triggered cloud agents instead. + +Many teams use both together: triggers for reactive workflows, and Scheduled Agents for proactive maintenance. diff --git a/src/content/docs/agent-platform/cloud-agents/viewing-cloud-agent-runs.mdx b/src/content/docs/agent-platform/cloud-agents/viewing-cloud-agent-runs.mdx new file mode 100644 index 0000000..d9b5b70 --- /dev/null +++ b/src/content/docs/agent-platform/cloud-agents/viewing-cloud-agent-runs.mdx @@ -0,0 +1,92 @@ +--- +title: Cloud agent session sharing +description: >- + Open, inspect, and steer remote cloud agent runs in real time from Warp or + the web. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Cloud agent session sharing lets you open, inspect, and continue interacting with agent tasks that are running on remote virtual machines. Whether a cloud agent was triggered from [integrations](/agent-platform/cloud-agents/integrations/) like Slack, Linear, GitHub Actions, or the [Oz CLI](/reference/cli/), you can view its full session, follow along in real time, ask follow-up questions, and even "fork" the work into your local Warp environment. + +<VideoEmbed url="https://www.loom.com/share/edd662da8de345ae979c4d39eb19c513" /> + +This makes cloud agent runs observable, steerable, and collaborative — even if they weren't initiated from your machine. + +--- + +### What it enables + +With cloud agent session sharing, you can view the full remote session for a cloud agent run and: + +* See every command the agent executed in the virtual environment +* Inspect context, logs, and outputs directly in Warp or the web viewer +* Ask follow-up questions or give additional instructions after the task completes +* Bring the conversation into your local Warp session with Fork to local +* Continue working on remote-generated code locally +* Share links so teammates can view or collaborate on the session + +Everything is accessible whether or not Warp is installed on the viewer’s machine. + +## How it works + +#### 1. Open a remote cloud agent run + +When a cloud agent starts working — for example, from a Slack mention, a Linear issue, or a [CLI](/reference/cli/) trigger — Warp attaches a shareable link to the run. + +* From [Slack](/agent-platform/cloud-agents/integrations/slack/), click **View Agent** in the agent response to open the session. +* From [Linear](/agent-platform/cloud-agents/integrations/linear/), click the ↗ **Warp** button ("Open in Warp") on the ticket to open the session. + +You can also open the session directly in your browser without installing Warp. Here, you’ll see the complete agent session running on a cloud VM, including all steps, logs, and context. + +#### 2. Inspect the session like it’s your own + +Once the session loads, you can: + +* Scroll through the cloud agent's actions +* See the prompt, plan, and decisions it made +* Review the code or config changes it produced +* Understand what environment it executed in + +You’re viewing a remote VM, but the UI behaves like a local Warp session. + +#### 3. Keep chatting with the remote agent + +Even if the cloud agent has completed its task, you can still ask follow-up questions or request more work. Warp sends your message back to the remote VM and continues the conversation. + +Examples: + +* “Can you explain which flag you changed?” +* “Give me a summary of what you modified.” +* “Show me the reasoning behind your last step.” + +This works as long as the remote environment is still active. + +#### 4. Handle inactive or shut-down sessions + +Cloud agent environments automatically shut down after a period of inactivity. When that happens, you'll see a notice that the virtual machine has been stopped. + +If you still want to continue the conversation or work on the code, you can click **Fork to local**. + +#### 5. Fork the session to your local Warp + +Forking brings the cloud agent conversation into your local machine, so you can pick up where the agent left off. + +Once forked: + +* The session appears as a normal conversation in your local Warp +* You can keep prompting the agent using all your local tools +* You can continue inspecting or modifying the generated code +* The agent responds using your local environment instead of the remote VM + +**Note:** If the cloud agent created a new git branch or repository in the remote VM, you'll need to clone that branch locally first so the agent can keep working on the same code. Warp will streamline this workflow in a future release. + +### Viewing sessions across devices + +Cloud agent sessions can be viewed from: + +* The Warp desktop app +* A browser via the web viewer +* Remote teammates using the shared link +* Local Warp sessions after forking + +You get consistent visibility into the work regardless of where you open it. diff --git a/src/content/docs/agent-platform/getting-started/agents-in-warp.mdx b/src/content/docs/agent-platform/getting-started/agents-in-warp.mdx new file mode 100644 index 0000000..81548d3 --- /dev/null +++ b/src/content/docs/agent-platform/getting-started/agents-in-warp.mdx @@ -0,0 +1,118 @@ +--- +title: Agents in Warp +description: >- + Warp's Oz agents are capable collaborators that help you write code, debug + issues, and complete terminal workflows, all from natural language prompts. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +<VideoEmbed url="https://youtu.be/qiQtD1jPF6s" title="Agent Mode Overview" /> + +Warp includes Oz agents. These coding agents are designed to help you build, test, deploy, and debug while keeping you in control. Describe what you want to do in natural language (_you can even use your voice_), and Oz will take action using your environment, codebase, and saved context. + +## What Oz agents can do + +Oz agents understand your codebase and can execute tasks autonomously while keeping you in control: + +* **Write and edit code** - Create new files, refactor existing code, or make changes across multiple files in your codebase +* **Debug and fix errors** - Analyze stack traces, interpret error output, and apply fixes +* **Run commands** - Execute shell commands and use the output to guide next steps +* **Recover from errors** - Automatically retry failed operations with adjustments +* **Learn tools** - Integrate with any CLI tool by reading its `--help` or public documentation +* **Use your context** - Leverage [Warp Drive](/knowledge-and-collaboration/warp-drive/), [MCP servers](/agent-platform/capabilities/mcp/), [Rules](/agent-platform/capabilities/rules/), and [codebase indexing](/agent-platform/capabilities/codebase-context/) for tailored responses + +**Try this prompt** — [_open in Warp_](https://app.warp.dev/drive/prompt/Clone-and-install-Warps-themes-repository-PkK9Zw16SCD3JKzOUoGuj4) + +```text +Detect my current operating system. Based on that, navigate to the appropriate Warp themes directory (e.g. ~/.warp/ on macOS). + +Then, clone the official Warp themes repository using SSH (git@github.com:warpdotdev/themes.git) into that directory, following the structure and instructions provided in the repo's README. If SSH does not work, try HTTPS (https://github.com/warpdotdev/themes.git) or via the GitHub CLI (gh repo clone warpdotdev/themes). +``` +--- + +## Agent autonomy + +Under **Settings** > **Agents** > **Profiles** > **Permissions**, you can control how much autonomy the agent has when performing different types of actions: + +* Reading files +* Creating plans +* Executing commands +* Calling MCP servers + +For each action, set the autonomy level to: + +* **Let the agent decide** - The agent chooses when to ask for confirmation +* **Always prompt for confirmation** - Require approval before each action +* **Always allow** - Execute without prompting +* **Never** - Disable this action entirely + +You can also configure an **allowlist** and **denylist** for specific commands you always want to run—either with or without confirmation. + +--- + +## Agent profiles + +Profiles let you define different permission and model configurations for different contexts. Create and manage profiles in **Settings** > **Agents** > **Warp Agent**, then switch between them by clicking the profile icon in Warp's input area. + +Common profile patterns: + +* **Default** - Balanced permissions for everyday use +* **YOLO mode** - Loose permissions for personal projects where you want the agent to move fast +* **Prod mode** - Restrictive permissions ("Always Ask") for high-risk environments like production servers + +For more details, see [Agent Profiles & Permissions](/agent-platform/capabilities/agent-profiles-permissions/). + +--- + +## Managing agents + +You can run multiple Oz agents simultaneously in Warp. All active agents—both local conversations and cloud agent runs—are tracked in the [management view](/agent-platform/cloud-agents/managing-cloud-agents/). + +Agents notify you when they need input, such as permission to run a command or approval to apply a code diff. This lets you focus on other work, knowing you'll be alerted when your attention is required. + +To access conversations across devices, share them with teammates, or restore past conversations, enable [cloud-synced conversations](/agent-platform/local-agents/cloud-conversations/). + +--- + +## Context and knowledge + +Oz agents work best when they understand your codebase and workflows. Warp provides several ways to give agents the context they need: + +* [**Codebase Context**](/agent-platform/capabilities/codebase-context/) - Warp indexes your Git-tracked files so agents can search and understand your code +* [**Rules**](/agent-platform/capabilities/rules/) - Define global and project-level guidelines that shape agent behavior +* [**Skills**](/agent-platform/capabilities/skills/) - Reusable instructions that teach agents how to perform specific tasks +* [**MCP Servers**](/agent-platform/capabilities/mcp/) - Connect external tools and data sources (GitHub, Linear, databases) to your agents +* [**Warp Drive**](/knowledge-and-collaboration/warp-drive/) - Save prompts, workflows, and notebooks that agents can reference + +--- + +## Third-Party CLI Agents + +In addition to Warp's built-in Oz agent, Warp provides first-class support for third-party CLI coding agents like Claude Code, Codex, and OpenCode. Run any supported agent inside Warp and get rich input, code review, agent notifications, vertical tabs with agent metadata, and more. + +→ [Learn about Third-Party CLI Agents](/agent-platform/cli-agents/overview/) + +--- + +## From local to cloud + +The same Oz agent capabilities that power interactive conversations in Warp also run in the cloud. Cloud agents can: + +* React to events from Slack, Linear, or GitHub +* Run on schedules for recurring tasks like dependency updates +* Execute in parallel across repos or tasks +* Produce tracked, auditable, shareable runs + +Cloud agents are ideal for work that doesn't need your immediate attention—PR reviews, issue triage, routine maintenance, and integration-driven workflows. + +→ [Learn about Cloud Agents](/agent-platform/cloud-agents/overview/) + +--- + +## Resources + +* [**Oz web app**](https://oz.warp.dev) - Create runs, manage schedules, browse skills, and configure integrations +* [**Warp Agents overview**](/agent-platform/local-agents/overview/) - Detailed guide to working with agents in Warp +* [**Capabilities**](/agent-platform/capabilities/) - All agent capabilities: planning, task lists, model choice, and more +* [**Oz CLI**](/reference/cli/) - Run agents from the command line +* [**Oz API & SDK**](/reference/api-and-sdk/) - Programmatic access to agent runs diff --git a/src/content/docs/agent-platform/getting-started/faqs.mdx b/src/content/docs/agent-platform/getting-started/faqs.mdx new file mode 100644 index 0000000..732a805 --- /dev/null +++ b/src/content/docs/agent-platform/getting-started/faqs.mdx @@ -0,0 +1,69 @@ +--- +title: Agent FAQs +description: >- + Frequently asked questions about Warp's AI features, including supported + models, privacy practices, credit limits, billing, and usage guidelines. +--- + +## General + +### What data is sent and/or stored when using Agents in Warp? + +See our [Privacy Page](/support-and-community/privacy-and-security/privacy/) for more information on how we handle data used by Agents in Warp. + +### What happened to the old Warp AI chat panel? + +Agent Mode has replaced the previous AI chat panel. Agent Mode is more powerful in all of the chat panel's use cases. Not only can Agent Mode run commands for you, it can also gather context without you needing to copy and paste. To start a similar chat panel, click the AI button in the menu bar to open a new AI pane. + +### Is my data used for model training? + +Warp reserves the right to use data collected to train models and improve Warp. Warp has Zero Data Retention with all its model providers (e.g. Anthropic, OpenAI, etc.). Please learn more about telemetry in our [Privacy Page](/support-and-community/privacy-and-security/privacy/). + +### What model are you using for Agent Mode? + +Warp supports a curated list of LLMs from providers like OpenAI, Anthropic, and Gemini. To view the full list of supported models and learn how to switch between them, visit the [Model Choice](/agent-platform/capabilities/model-choice/) page. + +### Can I use my own LLM API key? + +Warp supports [Bring Your Own Key (BYOK)](/support-and-community/plans-and-billing/bring-your-own-api-key/) for users on paid plans (starting with Build). You can connect your own Anthropic, OpenAI, or Google API keys to route requests directly through your account. Organizations on the Enterprise plan can additionally enable managed "Bring Your Own LLM" configurations to meet strict security or compliance requirements. + +## Billing + +Every Warp plan includes a set number of credits per user per month. See [pricing](https://www.warp.dev/pricing) to compare plans. + +Credit limits apply to Agent Mode, Generate (Legacy), and [AI autofill in Workflows](/knowledge-and-collaboration/warp-drive/workflows/#ai-autofill). + +For questions about what counts as a credit, what counts as a token, and how often credits refresh, see [Credits](/support-and-community/plans-and-billing/credits/) and the [Plans & Pricing](/support-and-community/plans-and-billing/plans-pricing-refunds/) page. + +## Common AI error messages + +#### **"Message token limit exceeded" error** + +This error means your input (plus attached context) exceeds the maximum context window of the model you're using. If you exceed the limit for your selected model, you may receive no output. + +To fix this, try: + +* Starting a new conversation +* Reducing the number of blocks or lines attached to your query + +#### "Monthly request limit exceeded" or "Monthly credit limit exceeded" errors + +Once you exceed your monthly credit limit (see [pricing](https://www.warp.dev/pricing) for current limits), premium models will be disabled until your quota resets at the start of your next billing cycle. On paid plans with Add-on Credits, you can continue using AI with usage-based billing. + +**Request failed with error: QuotaLimit** + +Once you exceed your AI token limits, all models will be disabled. Note that credits and tokens are calculated separately, and even though the plans may have a set number of credits, they also have a limited number of tokens. + +**Request failed with error: ErrorStatus (403, "Your account has been blocked from using AI features")** + +This message means your account has been blocked from using AI features, typically due to a violation of our [Terms of Service](https://www.warp.dev/terms-of-service) or suspected abuse (e.g. attempting to bypass credit or token limits). + +To resolve or clarify this, please contact our team at [appeals@warp.dev](mailto:appeals@warp.dev) if you believe this was an error. We'll review your case and respond as soon as possible. + +:::caution +Note that any error that does not mention appeals@warp.dev isn't related to being blocked and should be reported as feedback or a bug. See [Sending Us Feedback](/support-and-community/troubleshooting-and-support/sending-us-feedback/) for more. +::: + +## Gathering AI debugging ID + +In cases where you have issues with the Agent, we may ask for the AI debugging ID to troubleshoot the specific conversation. To gather the debugging ID, see [Gathering AI Debugging ID](/support-and-community/troubleshooting-and-support/sending-us-feedback/#gathering-ai-debugging-id) for detailed steps. diff --git a/src/content/docs/agent-platform/index.mdx b/src/content/docs/agent-platform/index.mdx new file mode 100644 index 0000000..10814d9 --- /dev/null +++ b/src/content/docs/agent-platform/index.mdx @@ -0,0 +1,52 @@ +--- +title: Agents overview +description: >- + Oz is the orchestration platform for cloud agents, powering both interactive + and autonomous agents for development workflows. +--- + +Warp includes **Oz**, the orchestration platform for cloud agents. While Warp provides the terminal and coding surface you work in day-to-day, Oz is the underlying orchestration layer that makes running agents at scale possible. + +Warp's client is open source under [AGPL v3](https://github.com/warpdotdev/warp/blob/master/LICENSE), so the editor and terminal that host your agents are fully auditable. See [Contributing to Warp](/support-and-community/community/contributing/) for the source and contribution flow. + +With Oz, you can: + +* Run interactive agent conversations in Warp for real-time coding assistance +* Deploy autonomous agents that run in the cloud from triggers, schedules, or integrations +* Coordinate multiple agents concurrently across machines, repos, and teams +* Track, audit, and share agent activity with full visibility into what ran and what it did + +Oz is fully programmable—launch agents manually or build custom logic around them with triggers, schedules, environments, and your choice of hosting (Warp's cloud or your own). + +--- + +## Key capabilities + +* [**Local Agents**](/agent-platform/local-agents/overview/) - Interactive Oz agents embedded in Warp. Use natural language to write code, debug issues, run commands, and automate development tasks with full terminal access. +* [**Third-Party CLI Agents**](/agent-platform/cli-agents/overview/) - Use Claude Code, Codex, OpenCode, and other CLI coding agents in Warp with rich input, notifications, code review, and remote session control. +* [**Oz Cloud Agents**](/agent-platform/cloud-agents/overview/) - Autonomous Oz agents that run in the background in response to system events, schedules, or integrations. +* [**Integrations**](/agent-platform/cloud-agents/integrations/) - Connect external system events to autonomous agent execution. Use [Slack](/agent-platform/cloud-agents/integrations/slack/), [Linear](/agent-platform/cloud-agents/integrations/linear/), [GitHub Actions](/agent-platform/cloud-agents/integrations/github-actions/), and other integrations to trigger agents in the cloud. +* [**Oz Platform**](/agent-platform/cloud-agents/platform/) - The underlying infrastructure that powers Oz, including the CLI, API/SDK, orchestration layer, environments, secrets, and management/observability. + +--- + +## Getting started + +* [**Agents in Warp**](/agent-platform/getting-started/agents-in-warp/) - Start using Oz agents interactively in Warp +* [**Oz web app**](https://oz.warp.dev) - Create runs, manage schedules, browse skills, and configure integrations +* [**Oz CLI**](/reference/cli/) - Run agents from the command line, in CI, or on remote machines +* [**Oz API & SDK**](/reference/api-and-sdk/) - Programmatically create and monitor agent runs + +--- + +## Learn more + +* [Warp Agents overview](/agent-platform/local-agents/overview/) - Interactive agents in Warp +* [Third-Party CLI Agents](/agent-platform/cli-agents/overview/) - Claude Code, Codex, OpenCode, and more +* [Cloud Agents Overview](/agent-platform/cloud-agents/overview/) - Background agents for automation at scale +* [Agent Capabilities](/agent-platform/capabilities/) - Skills, planning, MCP, rules, and more +* [Oz Platform](/agent-platform/cloud-agents/platform/) - CLI, API/SDK, orchestration, environments, and hosts +* [Environments](/agent-platform/cloud-agents/environments/) - Configure execution context for cloud agents +* [Integrations](/agent-platform/cloud-agents/integrations/) - Slack, Linear, GitHub Actions, and custom integrations +* [Skills as Agents](/agent-platform/cloud-agents/skills-as-agents/) - Run agents from reusable skill definitions +* [Managing Cloud Agents](/agent-platform/cloud-agents/managing-cloud-agents/) - Monitor and manage agent activity diff --git a/src/content/docs/agent-platform/local-agents/active-ai.mdx b/src/content/docs/agent-platform/local-agents/active-ai.mdx new file mode 100644 index 0000000..63f82f2 --- /dev/null +++ b/src/content/docs/agent-platform/local-agents/active-ai.mdx @@ -0,0 +1,76 @@ +--- +title: Active AI Recommendations +description: >- + Active AI Recommendations proactively suggest fixes and next actions based + on your command line errors, inputs, and outputs. +--- + +:::note +Active AI features can be disabled in **Settings** > **Agents** > **Warp Agent** with the Active AI toggle. +::: + +### Prompt Suggestions + +Prompt Suggestions are contextual, AI-powered suggestions that activate Agent Mode. These banners will provide suggestions for what to ask Agent Mode in specific scenarios, similar to how Warp already suggests commands to run. + +To disable, please visit **Settings** > **Agents** > **Warp Agent** > **Active AI** > **Prompt Suggestions** + +![Example of inline banner popping up when relevant contextually.](../../../../assets/agent-platform/prompt-suggestions-example-1.png) + +#### Accepting a prompt suggestion + +If you press `CMD-ENTER` (on macOS), `CTRL-SHIFT-ENTER` (on Linux/Windows), or click on the chip, the suggestion will auto-populate into your input and run against [Agent Mode](/agent-platform/local-agents/interacting-with-agents/) (with the most recent block attached). + +:::note +Prompt Suggestions use an LLM to generate prompts based on your terminal session, specifically the most recent block. These AI requests do not contribute towards your AI limits, however, any accepted prompts run in Agent Mode contribute as normal. Visit **Settings** > **Agents** > **Warp Agent** > **Active AI** if you'd like to turn it off. + +If [Secret Redaction](/support-and-community/privacy-and-security/secret-redaction/) is enabled, any selected regexes are applied to content sent to Active AI features to prevent any sensitive data being leaked. +::: + +![Setting for Prompt Suggestions](../../../../assets/agent-platform/prompt-suggestions-setting-1.png) + +### Next Command + +Next Command uses AI to suggest the next command to run based on your active terminal session and command history. It uses your active terminal session contents and an LLM to generate commands. + +To disable, please visit **Settings** > **Agents** > **Warp Agent** > **Active AI** > **Next Command** + +![Next Command suggestion appearing inline based on the active terminal session and command history.](../../../../assets/agent-platform/next-command.png) + +:::note +Next Command is an LLM-based feature that uses your command history (enriched with git branch, exit code, and directory metadata) as well as recent block input and output to generate the next command suggestions. + +[Secret Redaction](/support-and-community/privacy-and-security/secret-redaction/) is automatically applied to any content sent to Active AI features to prevent any sensitive data being leaked. +::: + +#### Accepting Next Command suggestions + +Press `→` or `CTRL-F` to accept a Next Command suggestion into your input buffer, then press `ENTER` to execute it. You can change the accept keybinding (for example, to `TAB`) via the inline keybinding picker that appears next to the suggestion. + +#### Billing + +Next Commands are unlimited across all of Warp's plans, including the Free plan. For the latest information on other AI limits and other pricing details, visit [warp.dev/pricing](https://warp.dev/pricing). + +### Suggested Code Diffs + +Suggested Code Diffs automatically surface potential fixes for command-line errors encountered within Warp. These are most often compiler errors, but they may also include other situations where Warp can confidently predict a straightforward resolution, such as simple merge conflicts. + +!["Generating fix" banner shown after a command-line error while Warp prepares a proposed diff.](../../../../assets/agent-platform/suggested-code-diffs-generating-fix.png) + +When an error occurs, Warp evaluates whether it is appropriate for an LLM to generate a fix. If so, a “Generating fix” banner will appear while Warp prepares a proposed diff. You can stop this process at any time by pressing `CTRL + C` or the stop button. + +![Suggested code diff with options to dismiss or accept the proposed fix.](../../../../assets/agent-platform/suggested-code-diffs.png) + +#### **Using a suggested code diff** + +Once the diff is generated, you can either dismiss it or accept it. Acceptance can be done directly via the buttons in the diff view, or with `CMD + ENTER` on macOS and `CTRL + ENTER` on Windows/Linux. + +You can also view additional details of the diff by pressing `CMD + E` (macOS) or `CTRL + E` (Windows/Linux), which expands the view to allow further inspection (including refining or editing it). You can also use `↓` to view the entire diff. + +**Billing** + +Suggested Code Diffs do not count toward your AI request limits. There are maximum limits to the number of code diffs surfaced per month, which scales based on your plan tier. For the latest details on plan limits and pricing, please visit [warp.dev/pricing](https://warp.dev/pricing). + +## Active AI privacy + +See our [Privacy Page](/support-and-community/privacy-and-security/privacy/) for more information on how we handle data with Active AI. diff --git a/src/content/docs/agent-platform/local-agents/agent-context/blocks-as-context.mdx b/src/content/docs/agent-platform/local-agents/agent-context/blocks-as-context.mdx new file mode 100644 index 0000000..6254c48 --- /dev/null +++ b/src/content/docs/agent-platform/local-agents/agent-context/blocks-as-context.mdx @@ -0,0 +1,100 @@ +--- +title: Blocks as Context +description: >- + Attach blocks from your terminal as context so Warp’s Agent can understand + errors, outputs, or previous commands when responding to your queries. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +## Attaching blocks as context + +Warp’s Agent can use blocks from your Agent conversations as context to better understand your queries and generate more relevant responses. + +You can attach a block directly from the terminal blocklist by clicking the AI sparkles icon on it and selecting “Attach as context.” + +![From a block of output, attach the block and ask Agent Mode to remove all untracked files.](../../../../../assets/agent-platform/remove_all_untracked_files.png) + +The most common use case is to ask the AI to fix an error. You can attach the error in a query to Agent Mode and type "fix it." + +**If you're already in Agent Mode, use the following ways to attach or clear context from your query:** + +<Tabs> + <TabItem label="macOS"> + **Attach a previous block** + + * To attach blocks to a query, you can use `CMD-UP` to attach the previous block as context to the query. While holding `CMD`, you can then use your `UP/DOWN` keys to pick another block to attach. + * You may also use your mouse to attach blocks in your session. Hold `CMD` as you click on other blocks to extend your block selection. + + **Clear a previous block** + + * To clear blocks from a query, you can use `CMD-DOWN` until the blocks are removed from context. + * You may also use your mouse to clear blocks in your session. Hold `CMD` as you click on an attached block to clear it. + + :::note + When using "Pin to the top" [Input Position](/terminal/appearance/input-position/), the direction for attaching or detaching is reversed (i.e. `CMD-DOWN` attaches blocks to context, while `CMD-UP` clears blocks from context). + ::: + </TabItem> + <TabItem label="Windows"> + **Attach a previous block** + + * To attach blocks to a query, you can use `CTRL-UP` to attach the previous block as context to the query. While holding `CTRL`, you can then use your `UP/DOWN` keys to pick another block to attach. + * You may also use your mouse to select blocks in your session. Hold `CTRL` as you click on other blocks to extend your block selection. + + **Clear a previous block** + + * To clear blocks from a query, you can use `CTRL-DOWN` until the blocks are removed from context. + * You may also use your mouse to clear blocks in your session. Hold `CTRL` as you click on an attached block to clear it. + + :::note + When using "Pin to the top" [Input Position](/terminal/appearance/input-position/), the direction for attaching or detaching is reversed (i.e. `CTRL-DOWN` attaches blocks to context, while `CTRL-UP` clears blocks from context). + ::: + </TabItem> + <TabItem label="Linux"> + **Attach a previous block** + + * To attach blocks to a query, you can use `CTRL-UP` to attach the previous block as context to the query. While holding `CTRL`, you can then use your `UP/DOWN` keys to pick another block to attach. + * You may also use your mouse to select blocks in your session. Hold `CTRL` as you click on other blocks to extend your block selection. + + **Clear a previous block** + + * To clear blocks from a query, you can use `CTRL-DOWN` until the blocks are removed from context. + * You may also use your mouse to clear blocks in your session. Hold `CTRL` as you click on an attached block to clear it. + + :::note + When using "Pin to the top" [Input Position](/terminal/appearance/input-position/), the direction for attaching or detaching is reversed (i.e. `CTRL-DOWN` attaches blocks to context, while `CTRL-UP` clears blocks from context). + ::: + </TabItem> +</Tabs> + +--- + +## Block visibility across views + +Blocks in Warp belong to either the terminal view or a specific agent conversation: + +* **Terminal blocks** - Commands you run directly in the terminal. These always appear in your terminal blocklist and can be attached as context to multiple conversations. +* **Agent conversation blocks** - Commands executed within an agent conversation (either by you or the agent). These only appear within that specific conversation and don't clutter your terminal blocklist. + +This separation keeps your terminal view clean while preserving full context within each conversation. + +--- + +## Automatic context in agent conversations + +When you're working inside an agent conversation, any shell commands you run are automatically included as context for your next query. This means you can: + +1. Run a command to see its output +2. Ask the agent about the results without manually attaching the block + +For example, in an agent conversation, run `npm test` and then ask "why did these tests fail?"—the test output is already part of the conversation context. + +You can also manually attach terminal view blocks to add additional context from commands you ran outside the conversation. + +--- + +## Pending and attached context + +When you select blocks in terminal view and start a new conversation, those blocks become **pending context**: + +* **Pending context** - Blocks are selected but the conversation hasn't started yet. If you deselect the blocks (`ESC` or `CMD-K` on macOS, `ESC` or `CTRL-K` on Windows/Linux), they're removed from the agent view. +* **Attached context** - Once you submit your first query, the pending blocks become attached to the conversation and remain part of the context. diff --git a/src/content/docs/agent-platform/local-agents/agent-context/images-as-context.mdx b/src/content/docs/agent-platform/local-agents/agent-context/images-as-context.mdx new file mode 100644 index 0000000..b4691c2 --- /dev/null +++ b/src/content/docs/agent-platform/local-agents/agent-context/images-as-context.mdx @@ -0,0 +1,38 @@ +--- +title: Images as Context +description: >- + Attach screenshots, diagrams, or other images to your prompt so Warp’s Agent + can use visual context when generating responses. +--- + +## **Attaching images as context** + +To provide visual context, you can attach images directly to an agent prompt. This is useful for including screenshots, diagrams, or other visual references alongside your query. + +You can attach images in the following ways: + +* Using the **image upload button** found on the toolbelt (either on the bottom left or right), depending on which input mode you're using: + +![Attaching 5 images on the new "Universal" input (bottom left toolbelt)](../../../../../assets/agent-platform/image-as-context-universal.png) + +![Attaching 4 images on the "Classic" input (bottom right)](../../../../../assets/agent-platform/image-as-context-classic.png) + +* Copy and paste images directly (e.g. right-click an image > "Copy image" or copy from a file manager) into Warp. +* Drag and drop images, such as from a file manager or screenshot utility. + +:::note +Warp accepts the following image formats: `.jpg` , `.jpeg` , `.png` , `.gif` , and .`webp` . +::: + +You can attach up to **5 images per request**, and up to **20 images across a single conversation**. Each image is sent to the model provider and immediately discarded — nothing is stored on Warp's servers. + +:::caution +**Cloud agent conversations do not currently support image attachments.** Image attachment is only available in local agent conversations. If you need to provide visual context to a cloud agent, describe the image contents in your prompt or reference the image file path within the cloud agent's [environment](/agent-platform/cloud-agents/environments/). +::: + +### Model behavior and image handling + +All supported models listed in [Model Choice](/agent-platform/capabilities/model-choice/) can interpret image input. + +Attaching images will consume additional requests, proportional to the number of images added. To stay within model limits, Warp will intelligently resize images before passing them as context, minimizing token usage and respecting the model's maximum image dimensions. + diff --git a/src/content/docs/agent-platform/local-agents/agent-context/index.mdx b/src/content/docs/agent-platform/local-agents/agent-context/index.mdx new file mode 100644 index 0000000..b511fc7 --- /dev/null +++ b/src/content/docs/agent-platform/local-agents/agent-context/index.mdx @@ -0,0 +1,22 @@ +--- +title: Agent Context +description: >- + How to attach various forms of multi-modal context directly to Warp's Agent + within a prompt. +--- + +In Warp, you can pass different types of input directly to the Agent to guide its behavior and improve response quality. These inputs are known as **Agent Context**: ad-hoc pieces of information you manually supply during a session. + +**You can attach context in several ways:** + +* [Blocks as Context](/agent-platform/local-agents/agent-context/blocks-as-context/) - share output from your terminal to help the Agent understand errors, logs, or previous commands. +* [Images as Context](/agent-platform/local-agents/agent-context/images-as-context/) - include screenshots, diagrams, or other visuals to provide additional clarity. +* [URLs as Context](/agent-platform/local-agents/agent-context/urls-as-context/) - attach public webpages so the Agent can extract and reference their content. +* [Selection as Context](/agent-platform/local-agents/agent-context/selection-as-context/) - attach code snippets from the editor or review panel to enrich your prompts with precise context. +* [Using @ to Add Context](/agent-platform/local-agents/agent-context/using-to-add-context/) - reference files, folders, code symbols, or Warp Drive objects directly in your prompts. + +Commands you run inside an agent conversation are automatically included as context for your next prompt. For details, see [Blocks as Context](/agent-platform/local-agents/agent-context/blocks-as-context/). + +--- + +This is distinct from other persistent or automatic sources of context, such as [Rules](/agent-platform/capabilities/rules/), [Warp Drive as Agent Mode Context](/knowledge-and-collaboration/warp-drive/agent-mode-context/), and [Model Context Protocol (MCP)](/agent-platform/capabilities/mcp/), which the Agent also uses when available. diff --git a/src/content/docs/agent-platform/local-agents/agent-context/selection-as-context.mdx b/src/content/docs/agent-platform/local-agents/agent-context/selection-as-context.mdx new file mode 100644 index 0000000..ba39a9f --- /dev/null +++ b/src/content/docs/agent-platform/local-agents/agent-context/selection-as-context.mdx @@ -0,0 +1,40 @@ +--- +title: Selection as Context +description: >- + Attach text or diffs directly from Warp’s editor or Code Review panel as + context for your Agent prompts. +--- + +### Attaching selections from Warp's native code editor + +When you have Warp’s [native code editor](/code/code-editor/) open beside a regular pane, you can easily attach specific lines of code as context: + +1. **Select text** in the editor. A tooltip will appear in the bottom-right corner of the selection. +2. **Add as context** by clicking the tooltip or using the keyboard shortcuts `Cmd + L` (macOS) or `CTRL + SHIFT + L` (Windows or Linux). +3. Warp automatically adds the relative file path and context, in addition to the line numbers of the hunk, as a formatted string into the prompt. + +This makes it easy to highlight just the lines you want the Agent to analyze or modify. + +![Selecting a function and attaching it as context from Warp's native code editor.](../../../../../assets/agent-platform/selection-as-context.png) + +### Attaching selections from Warp’s Code Review panel + +You can also directly attach context from the [Code Review panel](/code/code-review/): + +1. Hover over any **diff hunk** to reveal the option to attach it as context. + +![On-hover option to attach diff as context into the prompt.](../../../../../assets/agent-platform/Add-diff-as-context.png) + +2. Attaching a diff will automatically insert the relevant file path and changed lines into your prompt. + +This helps the Agent understand exactly what has been modified, making it easier to request explanations, feedback, or follow-up edits. + +![Code Review panel with diffs for review.](../../../../../assets/agent-platform/git-diff-full-view.png) + +### Attaching code to a third-party agent session + +You can select code, files, or snippets and feed them directly to a running third-party CLI agent session without copy-pasting or switching tools. + +When a third-party agent (Claude Code, Codex, OpenCode, etc.) is running in a Warp tab, select text in Warp's code editor or Code Review panel and attach it as context to that agent's session using `Cmd + L` (macOS) or `CTRL + SHIFT + L` (Windows/Linux). This works the same way as attaching context to Warp's built-in Agent. + +For more on third-party agent support, see [Third-Party CLI Agents](/agent-platform/cli-agents/overview/). diff --git a/src/content/docs/agent-platform/local-agents/agent-context/urls-as-context.mdx b/src/content/docs/agent-platform/local-agents/agent-context/urls-as-context.mdx new file mode 100644 index 0000000..8999060 --- /dev/null +++ b/src/content/docs/agent-platform/local-agents/agent-context/urls-as-context.mdx @@ -0,0 +1,20 @@ +--- +title: URLs as Context +description: >- + Attach a public URL to your prompt so the agent can reference that page's + content. +--- + +## Referencing websites via URLs + +You can attach a public URL to any prompt to provide page content as context. Warp will scrape the page and surface the extracted text directly to the model. + +* Only publicly accessible pages are supported. +* The full page is added to the model’s context, which may increase credit usage for long documents. +* Only the specific URL you provide is processed. The agent won’t explore the site, follow links, or crawl beyond that page. + +:::note +**Important**: URL attachments are different from web search. If you need the agent to look something up, gather real-time information, or pull in multiple sources, use [Web Search](/agent-platform/capabilities/web-search/) instead. +::: + +![Example of referencing docs via a URL](../../../../../assets/agent-platform/url-as-context.png) diff --git a/src/content/docs/agent-platform/local-agents/agent-context/using-to-add-context.mdx b/src/content/docs/agent-platform/local-agents/agent-context/using-to-add-context.mdx new file mode 100644 index 0000000..877724a --- /dev/null +++ b/src/content/docs/agent-platform/local-agents/agent-context/using-to-add-context.mdx @@ -0,0 +1,65 @@ +--- +title: "Using @ to Add Context" +description: >- + Use @ to reference files, folders, code symbols, and Warp Drive objects as + agent context. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +## How the @ context menu works + +You can attach specific files, folders, code symbols, Warp Drive objects, and blocks from other sessions as context to a prompt using the @ symbol. When you’re inside a **Git repository**, typing @ opens a context menu that allows you to search for and select files or directories to include. + +:::note +Attaching context with @ works in **both natural language mode** (when interacting with Agents) and **classic terminal commands** for referencing file paths. +::: + +**Note**: the search in the @-context menu is always relative to the root of the Git repository, even when you're working in a subdirectory. This means you can reference _any_ file or folder tracked in the repo, regardless of the current working directory. + +![Using the @ symbol to search for and attach a file or folder from the project root.](../../../../../assets/agent-platform/at-context.png) + +Additionally, no codebase indexing (via [Codebase Context](/agent-platform/capabilities/codebase-context/)) is required — file search is available immediately in any Git-initialized directory. The search also respects `.gitignore` rules and will exclude ignored files from the results. + +![Filtering files using @app to locate files containing “app” in their name or path.](../../../../../assets/agent-platform/at-context-app.png) + +![Referencing a folder or all files within it by typing @styles.](../../../../../assets/agent-platform/at-context-styles.png) + +### Referencing code symbols + +The @ menu can also be used to fuzzy-search for code symbols in your codebase. This includes functions, classes, interfaces, etc. + +If you type something like `@main`, Warp will surface a matching `main()` function and insert it into your prompt as a reference with the line number. By pointing the Agent to a specific symbol, you can give it exactly the context it needs to make a targeted edit or explanation. + +<VideoEmbed url="https://www.loom.com/share/da0c491bd2a44ed58d4fbdf2c260b019" /> + +### Referencing Warp Drive objects + +Warp Drive objects are another way to attach context with **@**. You can reference: + +* [Workflows](/knowledge-and-collaboration/warp-drive/workflows/) — parameterized commands you can name and save in Warp with descriptions and arguments. +* [Notebooks](/knowledge-and-collaboration/warp-drive/notebooks/) — runnable documentation consisting of markdown text and list elements, code blocks, and runnable shell snippets that can be automatically executed in your terminal session. +* [Rules](/agent-platform/capabilities/rules/) — reusable guidelines and constraints that inform how Agents respond to your prompts. + +When you select one of these objects, Warp inserts a reference token into your prompt. The contents of the object are then automatically passed as context to the Agent. + +<VideoEmbed url="https://www.loom.com/share/abd065af9fea421d925664135341c682" /> + +### Referencing blocks from other sessions + +You are not limited to the current terminal session. With @, you can also bring in blocks of output from earlier sessions. + + In the demo below, Ian shows how he previously ran cargo clippy and now wants help fixing the reported errors. Typing `@cargo clippy` surfaces the relevant block, which you can insert into your prompt. Once added, the Agent parses the output and generates fixes or explanations directly. + +You can also reference live blocks, not just those that have already completed execution. + +<VideoEmbed url="https://www.loom.com/share/a4e72847341044cca2fed59a6299e1b7" /> + +### Why @ to reference context? + +Attaching context with @ helps you: + +* Reference exact outputs instead of copy-pasting entire logs +* Attach relevant files or directories without leaving Warp +* Reuse existing context and knowledge in Warp Drive + +This makes Agent interactions more accurate, clearer, and efficient, without additional setup. diff --git a/src/content/docs/agent-platform/local-agents/cloud-conversations.mdx b/src/content/docs/agent-platform/local-agents/cloud-conversations.mdx new file mode 100644 index 0000000..07a983b --- /dev/null +++ b/src/content/docs/agent-platform/local-agents/cloud-conversations.mdx @@ -0,0 +1,138 @@ +--- +title: Cloud-synced conversations +description: >- + Sync agent conversations to the cloud to access them across devices, share + with teammates, and continue past conversations from anywhere. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Warp can sync your [agent conversations](/agent-platform/local-agents/interacting-with-agents/) to the cloud, making them accessible across devices, shareable with teammates, and persistent even after logging out. This enables you to pick up where you left off on any machine, share context with collaborators, and access past [cloud agent](/agent-platform/cloud-agents/overview/) conversations. + +## Key capabilities + +* **Persistence across devices** - Your conversations remain available when you log out and back in, or switch to a different machine. +* **Access to past cloud agent conversations** - View and restore cloud agent conversations after they complete. +* **Link sharing with access controls** - Share conversations with specific teammates or your team, with configurable permissions. +* **Web viewing** - View shared conversations in a browser without installing Warp. +* **Local continuation** - Restore any cloud conversation and continue it locally on your machine. + +<VideoEmbed url="https://www.loom.com/share/54038cf41219485dad3adb1d811e7e9a?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Cloud-synced conversations" /> + +## Enabling cloud conversations + +Cloud conversation sync is controlled by a setting in Warp: + +1. Open **Settings** > **Privacy** +2. Enable **Store AI conversations in the cloud** + +When enabled, your Agent conversations automatically sync to the cloud as you interact with the Agent. When disabled, conversations are stored locally on your machine only. + +:::caution +If cloud conversations are disabled, conversation data is lost when you log out and cannot be shared with others. Cloud agent conversations are always stored in the cloud regardless of this setting. +::: + +## How it works + +### Conversation syncing + +When cloud conversations are enabled, Warp automatically syncs your conversation data after each Agent interaction. This happens in the background and does not affect your workflow. + +Cloud conversations store a snapshot of the conversation state at each sync point. If you open the same conversation on two different machines, each continues independently from that snapshot—changes on one machine do not sync to the other in real time. + +### Continuing vs. forking + +When you restore a cloud conversation: + +* **Your own conversations** - You can continue the conversation directly, and updates sync back to the cloud. +* **Shared conversations from others** - Continuing creates a fork, giving you a new conversation that starts with the shared context but does not modify the original. + +This behavior mirrors [Conversation Forking](/agent-platform/local-agents/interacting-with-agents/conversation-forking/), where you branch off to explore a different direction without affecting the source conversation. + +## Managing cloud-synced conversations + +Cloud-synced conversations appear in all the usual conversation management entrypoints alongside your local conversations. You can browse, search, restore, and delete them just like any other conversation. + +See [Interacting with Agents](/agent-platform/local-agents/interacting-with-agents/) for detailed information on navigating and managing conversations, including keyboard shortcuts and the Conversation Panel in [Terminal and Agent modes](/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes/). + +* **Browse** - View all your local and cloud-synced conversations in one place. +* **Search** - Find conversations by title or content. +* **Restore** - Click a conversation to load it into your current session and continue where you left off. +* **Delete** - Remove conversations you no longer need. Deletion is permanent and immediate. + +--- + +## Sharing conversations + +You can share any cloud conversation with teammates via a link. + +### Creating a share link + +To share a conversation: + +1. Open the conversation you want to share +2. Access the share options through the conversation menu +3. Configure access permissions: + * **Anyone on your team** (default) - All team members can view + * **Specific people** - Enter email addresses to grant access + * **Anyone with the link** - No authentication required + +By default, shared conversations are visible to anyone on your team. + +### Viewing shared conversations + +Recipients can view shared conversations in two ways: + +* **On the web** - Open the link in a browser to view the conversation transcript without installing Warp. +* **In Warp** - Click "Open in Warp" to load the conversation in the desktop app, where you can continue it locally. + +When you continue a shared conversation from someone else, Warp creates a fork so you can build on the shared context without modifying the original. + +:::note +Cloud-synced conversations store snapshots of conversation data. For real-time collaboration on a live session, use [Agent Session Sharing](/agent-platform/local-agents/session-sharing/). +::: + +## Cloud agent conversations + +[Cloud agents](/agent-platform/cloud-agents/overview/) run in the cloud, and their conversations are automatically stored regardless of your local cloud conversations setting. + +### Accessing cloud agent conversations + +You can access any past cloud agent conversation: + +* **View transcripts** - Access the full conversation history of any past cloud agent run. +* **Restore locally** - Load a cloud agent conversation into your local Warp session to review or continue the work. + +This is useful when a cloud agent completes a task and you want to review what it did or continue from where it left off. + +--- + +## Privacy and data + +### Enterprise controls + +Enterprise administrators can disable cloud conversation storage for their organization through the [Admin Panel](/knowledge-and-collaboration/admin-panel/). + +When cloud conversation storage is disabled by your organization: + +* Conversations are stored locally only and not synced to the cloud +* You cannot share conversations or access them across devices +* Cloud agent conversations are still accessible through the Warp dashboard + +### Storage limits + +Cloud conversation storage limits vary by plan. For free users, Warp automatically removes the oldest cloud conversations when you reach your limit to make room for new ones. Your conversations are always preserved locally on your machine—only the cloud-synced copies are removed. + +For current storage limits by plan, see our [pricing page](https://www.warp.dev/pricing). + +### Deleting conversations + +When you delete a conversation, it is removed permanently and immediately. Make sure you no longer need a conversation before deleting it. + +--- + +## Related features + +* [Interacting with Agents](/agent-platform/local-agents/interacting-with-agents/) - Learn about conversation mechanics, follow-ups, and context windows. +* [Conversation Forking](/agent-platform/local-agents/interacting-with-agents/conversation-forking/) - Branch conversations to explore different directions. +* [Session Sharing](/agent-platform/local-agents/session-sharing/) - Collaborate in real time on a live Agent session. +* [Cloud Agents Overview](/agent-platform/cloud-agents/overview/) - Run agents in the cloud from triggers, schedules, or integrations. diff --git a/src/content/docs/agent-platform/local-agents/code-diffs.mdx b/src/content/docs/agent-platform/local-agents/code-diffs.mdx new file mode 100644 index 0000000..ecf1762 --- /dev/null +++ b/src/content/docs/agent-platform/local-agents/code-diffs.mdx @@ -0,0 +1,61 @@ +--- +title: Code Diffs +description: >- + How to review, refine, and apply code changes generated by Warp’s Agents + with the built-in diff editor in Agent Conversations. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +## Reviewing code diffs + +During an Agent Conversation, Warp can generate code diffs that open directly in a built-in diff editor. + +This lets you review proposed changes line by line, refine them with natural language, or make manual edits before choosing whether to apply them. It’s a fast, transparent way to stay in control of agent-generated code. + +:::caution +If the `Apply Code Diffs` permission is set to `Always allow` in [Agent Profiles & Permissions](/agent-platform/capabilities/agent-profiles-permissions/), code diffs are applied automatically without being surfaced for review. If it's set to `Agent decides` or `Always ask`, you'll always be prompted to review diffs before they're applied. +::: + +:::note +Code diffs generated by Warp are never stored on our servers. Warp's coding agent only works on local repositories. The agent can make changes on remote or docker repositories, but falls back to using terminal commands (i.e. `sed`, `grep` ) to make the changes. +::: + +![A code diff surfaced in an Agent Conversation.](../../../../assets/agent-platform/generated_blocklist_diff.png) + +You can also choose whether Warp automatically opens the [Code Review](/code/code-review/) panel the first time you accept a diff in a conversation. + +## **Navigating and applying diffs** + +When an Agent generates a code diff, Warp opens it in a built-in text editor with a visual diff view. Changes are grouped into clear hunks for easy inspection. + +* Use the `UP` and `DOWN` arrow keys (or mouse clicks) to move between hunks. +* For multi-file changes, use `LEFT` and `RIGHT` arrow keys to switch between files. +* Once satisfied with the changes, you can apply the diffs using `ENTER` or clicking "**Accept Changes**" to apply the modifications. + +:::caution +These modifications will not be applied to the files unless you explicitly accept them. +::: + +## **Refining or editing the diffs** + +If the initial suggestion needs more work: + +* Press `R` or select the "**Refine**" button to provide follow-up instructions in natural language. The agent will regenerate the diff based on your input. +* To manually adjust the code, press `E` or click "**Edit**" to switch into an editable view. +* To cancel a pending operation, use `CTRL-C` (on macOS, Windows, or Linux). Similarly, you can exit the editor at any time with `ESC` . + +:::note +You can open up code files in Warp in various different ways, refer to: [Opening files in Warp](/code/code-editor/#opening-files-in-warp) +::: + +![Editing a code diff directly in Warp's native code editor](../../../../assets/agent-platform/editting_diff.png) + +## Accepting diffs and continuing in Agent Mode + +When the Agent generates a code diff outside of an active conversation — for example, from a suggested code banner or a passive recommendation — you can accept the diff and seamlessly continue in Agent Mode. After accepting, Warp opens (or returns to) the Agent conversation with the applied changes as context, so you can immediately ask follow-up questions or request further modifications without starting a new conversation. + +### Demo: Editing Agent Code in Warp + +Here's an example from [Warp Guides](/guides/), where Zach demonstrates how to review and edit Agent code diffs natively in Warp: + +<VideoEmbed url="https://www.youtube.com/watch?time_continue=111&v=dm-P63USsVg" /> diff --git a/src/content/docs/agent-platform/local-agents/generate.mdx b/src/content/docs/agent-platform/local-agents/generate.mdx new file mode 100644 index 0000000..327f649 --- /dev/null +++ b/src/content/docs/agent-platform/local-agents/generate.mdx @@ -0,0 +1,84 @@ +--- +title: Generate (Legacy) +description: >- + Use natural language to look up commands or input, accessible either + directly from the command-line input or inside any interactive command or + program. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +## What is Generate? + +Generate helps turn natural language queries into precise commands as terminal input or contextual suggestions inside interactive commands and programs, whether you're using psql, gdb, git, mysql, or any other CLI tool. + +Generate is backed by Large Language Models from API providers like OpenAI and Anthropic, and are completely opt-in. + +:::note +Currently, you need to be online to use this feature. If this feature doesn't work, your ISP or firewall may be blocking the calls to `app.warp.dev` +::: + +## Ways to Generate with AI + +### Generate commands as command-line input + +Type `#` on the command-line input to generate command suggestions. + +![Typing '#' on the command line opens the suggestions interface](../../../../assets/agent-platform/open-ai-commands.png) + +<VideoEmbed url="https://www.loom.com/share/424a763ef0c8455e8269e541301968f2" title="Generating commands as command-line input demo" /> + +1. Press `` CTRL-` `` or type `#` into the text input editor to search using natural language. +2. Type in the input box what you'd like to do. For example, "replace a string in a file." +3. Results are generated in real-time, and you can keep the current prompt or modify the prompt to generate new commands. +4. When you've found the command you want to execute, it can be run or saved as a Workflow onto Warp Drive to easily recall it in the future. + +### \[Legacy] Generate text and contextual suggestions in interactive CLIs + +:::caution +**Our legacy Generate feature which works in interactive CLIs has been replaced by** [Full Terminal Use](/agent-platform/capabilities/full-terminal-use/)**, where Warp's agent can now run and control long-running or full-screen terminal applications**.\ +The agent can provide input when prompted, navigate interactive screens, and continue execution without stalling. +::: + +In interactive CLI applications, you can generate input using natural language. + +![Generate a SQL query](../../../../assets/agent-platform/generate-psql.png) + +![Generate Vim input](../../../../assets/agent-platform/generate-vim.png) + +<Tabs> + <TabItem label="macOS"> + 1. Inside a long-running, interactive command, press `CMD-I` when you see the hint text appear. + 2. Type what you would like to generate in the input box. For example, "show me all tables in my Postgres database" or in Vim, "generate a recursive Fibonacci function and save it to the file." + 3. Results are generated in real time using the [LLM of your choice](/agent-platform/local-agents/generate/#supported-interactive-cli-models). + 4. To refine or follow up on your query, press `CMD-Y`. You can then either edit your last message by pressing `UP ↑` or add a follow-up by typing in new text. + 5. When you've found the text you want to add or execute, press `Enter` or click the Accept button. + </TabItem> + <TabItem label="Windows"> + 1. Inside a long-running, interactive command, press `CTRL-SHIFT-I` when you see the hint text appear. + 2. Type what you would like to generate in the input box. For example, "show me all tables in my Postgres database" or in Vim, "generate a recursive Fibonacci function and save it to the file." + 3. Results are generated in real time using the [LLM of your choice](/agent-platform/local-agents/generate/#supported-interactive-cli-models) + 4. To refine or follow up on your query, press `CTRL-SHIFT-Y`. You can then either edit your last message by pressing `UP ↑` or add a follow-up by typing in new text. + 5. When you've found the text you want to add or execute, press `Enter` or click the Accept button. + </TabItem> + <TabItem label="Linux"> + 1. Inside a long-running, interactive command, press `CTRL-SHIFT-I` when you see the hint text appear. + 2. Type what you would like to generate in the input box. For example, "show me all tables in my Postgres database" or in Vim, "generate a recursive Fibonacci function and save it to the file." + 3. Results are generated in real time using the [LLM of your choice](/agent-platform/local-agents/generate/#supported-interactive-cli-models) + 4. To refine or follow up on your query, press `CTRL-SHIFT-Y`. You can then either edit your last message by pressing `UP ↑` or add a follow-up by typing in new text. + 5. When you've found the text you want to add or execute, press `Enter` or click the Accept button. + </TabItem> +</Tabs> + +A couple of other examples of interactive CLIs where you can invoke Generate: + +* **Database REPL** (e.g. `psql`, `mysql`, `sqlite`): Generate SQL queries such as "create a table to store user data" or "show me all the rows in orders for the last month" +* **Text editors** (e.g. `vim`, `nano`): Quickly generate text such as a markdown header, a code block comment, or a boilerplate CSS class. +* **Python REPL** (e.g. `ipython`, `python`): Quickly generate Python snippets such as "create a simple plot of x" or "write a unit test for this function" +* **Debugger tools** (e.g. `gdb`, `lldb`): Get commands for setting breakpoints or inspecting memory +* **Version control** (e.g. `git rebase -i`): Speed up complex git commands by describing your goal such as "interactively rebase master onto feature-branch" +* **Cloud provider shells** (e.g. `gcloud`, `aws cli`): faster setup or resource management such as "create a new Kubernetes cluster" or "provision a new RDS instance" + +:::caution +If you experience any issues with Generate, please visit known issues for [troubleshooting steps](/support-and-community/troubleshooting-and-support/known-issues/#online-features-dont-work). +::: diff --git a/src/content/docs/agent-platform/local-agents/interacting-with-agents/conversation-forking.mdx b/src/content/docs/agent-platform/local-agents/interacting-with-agents/conversation-forking.mdx new file mode 100644 index 0000000..ad1b06c --- /dev/null +++ b/src/content/docs/agent-platform/local-agents/interacting-with-agents/conversation-forking.mdx @@ -0,0 +1,106 @@ +--- +title: Conversation Forking +description: >- + Branch into a new agent thread with full context to explore alternatives + without altering the original conversation. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Warp allows you to **fork conversations** to create a new thread that inherits all of the context, messages, and history from an existing conversation. This is useful when you want to branch off in a new direction without affecting the original conversation. + +<VideoEmbed url="https://www.loom.com/share/15164f2abc19437ebefb47a8c6b52eb8?t=54" /> + +### How conversation forking works + +* When you fork a conversation, the new thread starts with the same context and history as the original. +* Any follow-ups in the forked conversation do **not** impact the original. Likewise, continuing in the original conversation does not change the fork. +* Forked conversations behave just like any other conversation: you can move them into new windows, panes, or tabs. +* Your selected model and execution profile are preserved in the forked conversation. + +_Example_: You can fork a conversation to explore an alternate solution, ask “what if” questions, or continue down two separate paths in parallel. + +### How to fork a conversation + +There are five ways to fork an existing conversation: + +#### **1. From the Command Palette** + +Open the menu using the Command Palette (`CMD + Y` on macOS / `CTRL + SHIFT + Y` on Windows/Linux). + +Select **Fork current conversation** to fork your current conversation, or fork a specific conversation from open conversations. + +![Command Palette showing the Fork current conversation option highlighted](../../../../../assets/agent-platform/conversation-forking-palette.png) + +In addition, when you hover over any open conversation in the Command Palette, you'll see a **fork button**. This lets you fork not only active conversations, but also inactive and historical ones. + +![Command Palette listing open conversations with a fork button visible on hover](../../../../../assets/agent-platform/conversation-forking-open-conversations.png) + +You can also access this conversation view from the conversation chip in the current conversation. + +![Conversation chip in the input area showing the Manage conversations shortcut](../../../../../assets/agent-platform/conversation-forking-chip.png) + +#### **2. From the footer of the most recent AI response block** + +In any conversation in the blocklist, click the **fork button** in the footer of the most recent AI block. A new conversation opens in a separate pane with the full context of the original. + +![Fork conversation button in the footer of the most recent agent response block](../../../../../assets/agent-platform/conversation-forking-footer.png) + +#### **3. Using the `/fork` slash command** + +Type `/fork` in the input to fork the current conversation. You can optionally include a prompt after the command, and Warp will send that prompt in the newly forked conversation. + +* Press `Enter` to open the fork in a new pane (default) +* Press `⌘+Enter` (macOS) or `Ctrl+Enter` (Windows/Linux) to open the fork in the current pane + +_Example_: `/fork Can you try a different approach?` Forks the selected conversation and immediately sends `Can you try a different approach?` in the forked conversation. + +#### **4. Using the /fork-and-compact slash command** + +Type `/fork-and-compact` to fork the current conversation and automatically compact the forked version. This combines forking with [context window management](/agent-platform/local-agents/interacting-with-agents/#context-window-management), giving you a fresh start with a summarized context. + +* Press `Enter` to open the fork in a new pane (default) +* Press `⌘+Enter` (macOS) or `Ctrl+Enter` (Windows/Linux) to open the fork in the current pane + +![Using the /fork-and-compact slash command to fork and summarize a conversation](../../../../../assets/agent-platform/conversation-fork-and-compact.png) + +#### **5. Using the `/fork-from` slash command** + +Type `/fork-from` to open a searchable menu of all queries in the current conversation. Select a query to fork the conversation from that specific point—everything up to and including that exchange is included in the fork, but subsequent messages are excluded. + +This is a more discoverable alternative to right-clicking on an agent response block. + +### Fork from anywhere in a conversation + +In addition to forking from the end of a conversation, you can fork from any point in the conversation history. This lets you return to an earlier agent response and branch off in a new direction from there. + +<VideoEmbed url="https://youtu.be/SlhF4_0bBxY" /> + +To fork from a specific point, **right-click** on any agent response block or click the three-dot menu in the top-right corner of the block. + +* Select **Fork conversation from here** to create a new conversation that includes everything up to and including that response, but excludes any queries or responses that came after it. + +**This is particularly useful for:** + +* **Exploring alternate paths** - Go back to a point where the conversation was on track and try a different approach. +* **Managing your context window** - If a conversation has grown too long, fork from an earlier point to continue with only the relevant context. +* **Preventing context pollution** - When a conversation has accumulated errors or gone off track, fork from before those issues occurred to start fresh. + +### Settings + +You can configure the default layout for forked conversations in **Settings** > **Features** > **Open forked conversation layout**: + +* **Split Pane** (default): Opens the forked conversation in a new pane alongside your current view. +* **New Tab**: Opens the forked conversation in a new tab. + +This setting controls the default behavior when forking via the Command Palette, AI block footer button, or slash commands (when pressing `Enter`). + +### Using forked conversations + +* Once forked, you can continue prompting as if you were still in the original conversation. The original conversation remains unchanged, allowing you to reference or continue both in parallel. +* For example, after forking you can ask _"Could you explain more?"_ and Warp responds using the inherited context. + +**Forking is especially useful when:** + +* You want to explore different approaches without losing the original thread. +* You need to keep one conversation "clean" while experimenting in another. +* You want to reuse context or specific blocks from older conversations. diff --git a/src/content/docs/agent-platform/local-agents/interacting-with-agents/index.mdx b/src/content/docs/agent-platform/local-agents/interacting-with-agents/index.mdx new file mode 100644 index 0000000..d1a0ec4 --- /dev/null +++ b/src/content/docs/agent-platform/local-agents/interacting-with-agents/index.mdx @@ -0,0 +1,242 @@ +--- +title: Interacting with agents +description: >- + Manage agent conversations across sessions with follow-ups, context blocks, + and multi-thread support. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +## Conversations with Warp's Agent + +Conceptually, a conversation is a sequence of AI queries and blocks. Conversations are tied to sessions and you can run multiple Agent Mode conversations simultaneously in different windows, tabs, or panes. + +Conversations work best when the queries are related. If your new question builds on the last one, continue in the same conversation. If it is unrelated, it is better to start a new one so that the context remains relevant. + +:::note +Long conversations can cause slower performance and lower-quality answers. When working on a separate task or question, start fresh rather than relying on context from earlier interactions. +::: + +:::note +To access conversations across devices, share them with teammates, or restore past cloud Agent conversations, enable [Cloud-synced Conversations](/agent-platform/local-agents/cloud-conversations/). +::: + +### Staying in a conversation (follow-ups) + +By default, if you ask an AI query immediately after interacting in Agent Mode, your query is sent as a **follow-up** to the current conversation. + +* In **Classic Input**, you'll see both the pink highlight bar on the left side of the block and a bent follow-up arrow (↳) next to your input. The conversation input chip also shows which conversation you are in. +* In **Terminal and Agent modes** (the default), the conversation view provides a dedicated space for multi-turn interactions. The conversation panel shows which conversation you are in. + +**To follow-up on a previous conversation:** + +* Simply continue prompting the agent if you are already in an active conversation. +* Open the **Conversations menu** (`CMD + Y` on macOS, `CTRL + SHIFT + Y` on Windows/Linux), select a conversation, and then enter your query. +* Alternatively, click the pink conversation chip in the input field to resume. + +![Continuing an Agent conversation in Classic Input (with indicator)](../../../../../assets/agent-platform/classic-input-follow-up.png) + +![Continuing an Agent conversation in agent conversation view](../../../../../assets/agent-platform/follow-up-universal-input.png) + +#### Agent tips in the input + +While Warp’s agent is thinking and processing your request, Warp may surface short tips with helpful workflows and ways to use Warp. These tips appear under the Warping indicator. + +![Agent tips appearing under the Warping indicator while the agent processes a request.](../../../../../assets/agent-platform/agent-tips.png) + +You can enable or disable these tips in two places: + +* **Settings**: **Settings** > **Agents** > **Warp Agent** > **Input** > **Show agent tips** +* **Command Palette**: Open the Command Palette (`CMD + P` on macOS, `CTRL + SHIFT + P` on Windows/Linux), then select "**Show Agent Tips**" or "**Hide Agent Tips**" + +### **Managing conversations** + +You can view previous conversations or start a new conversation via the **Conversations Menu** (`CMD + Y` on macOS, `CTRL + SHIFT + Y` on Windows/Linux). + +<VideoEmbed url="https://www.loom.com/share/9cc2451412be43e389a6b1414ea185e4?sid=4457ba14-4876-4988-ade6-1dca43dda96a" /> + +:::note +The "New Conversation" item disappears once you start searching for an actual conversation. +::: + +### **Starting a new conversation** + +Warp automatically creates a new conversation in a few situations. For example, if you ask an AI query after running a shell command or if three hours pass without activity, Agent Mode will start a fresh conversation. + +Visual indicators differ slightly depending on input mode: + +* In **Classic Input,** a new conversation begins when there is no follow-up arrow (↳) next to your input. +* In **Terminal and Agent modes**, starting a new conversation opens a fresh conversation view. Use the conversation panel to see all active and past conversations. + +<Tabs> + <TabItem label="macOS"> + You can also start a new conversation manually at any time: + + * In **Classic Input**, press `CMD + I` or press `BACKSPACE` while in follow-up mode. + * In **Terminal and Agent modes**, press `CMD + ↵` to start a new conversation, or use the `/new` slash command. + * Open the **Conversations Menu** using `CMD + Y` and select "New Conversation". + </TabItem> + <TabItem label="Windows"> + You can also start a new conversation manually at any time: + + * In **Classic Input**, press `CTRL + I` or press `BACKSPACE` while in follow-up mode. + * In **Terminal and Agent modes**, press `CTRL + SHIFT + ↵` to start a new conversation, or use the `/new` slash command. + * Open the **Conversations Menu** using `CTRL + SHIFT + Y` and select "New Conversation". + </TabItem> + <TabItem label="Linux"> + You can also start a new conversation manually at any time: + + * In **Classic Input**, press `CTRL + I` or press `BACKSPACE` while in follow-up mode. + * In **Terminal and Agent modes**, press `CTRL + SHIFT + ↵` to start a new conversation, or use the `/new` slash command. + * Open the **Conversations Menu** using `CTRL + SHIFT + Y` and select "New Conversation". + </TabItem> +</Tabs> + +![Starting a new Conversation in Classic Input](../../../../../assets/agent-platform/classic-input-new-convo.png) + +![Starting a new Agent Conversation in agent conversation view](../../../../../assets/agent-platform/universal-input-new-convo.png) + +## Context window management + +Every conversation with an agent consumes tokens stored in a **context window**. The context window (sometimes called _context length_) is the amount of text (measured in tokens) that a Large Language Model (LLM) can process at one time. **The size of the context window depends on the model you are using.** + +As tokens accumulate and exceed the context window, performance and response quality may degrade. If the context window is exceeded, the model may lose track of earlier parts of the conversation, and **Warp will automatically summarize the conversation to free up space**. + +### Warp provides a **context window usage indicator** to help you track this: + +When less than 20% of the window is used, no indicator is shown. As more tokens accumulate, the usage bar progresses to reflect how much of the context window has been consumed. + +![Context window usage indicator in its early state, with light usage shown.](../../../../../assets/agent-platform/context-window-1.png) + +![Context window usage indicator filling further as more tokens accumulate.](../../../../../assets/agent-platform/context-window-2-1.png) + +As you approach the limit, the indicator turns red to warn that the context window is nearly full. + +![Context window usage indicator turning red as the conversation approaches the model's context limit.](../../../../../assets/agent-platform/context-window-2.png) + +Once the limit is exceeded, Warp automatically summarizes the conversation so you can continue without losing important context. + +![Context window indicator after Warp automatically summarizes the conversation to free up space.](../../../../../assets/agent-platform/context-window-3.png) + +The context window usage indicator is available in agent conversation views. + +:::note +If you switch models during a conversation, the context usage indicator updates only after you send your next message. +::: + +## Conversation segmentation + +Warp automatically detects when your query has shifted to a new topic. When this happens, it suggests starting a new conversation instead of continuing in the same context. + +These options appear in the blocklist, where you can decide whether to branch off into a new conversation or keep going with the current one. + +![Suggestion in the blocklist to start a new conversation when Warp detects a topic shift.](../../../../../assets/agent-platform/conversation-segmentation.png) + +You can also create a new conversation manually at any time by using the keyboard shortcut, opening a new tab, or opening a new pane. + +<Tabs> + <TabItem label="macOS"> + * Start a new conversation: `CMD + SHIFT + N` + * Open a new tab: `CMD + T` + * Open a new pane: `CMD + D` + </TabItem> + <TabItem label="Windows"> + * Start a new conversation: `CTRL + SHIFT + N` + * Open a new tab: `CTRL + SHIFT + T` + * Open a new pane: `CTRL + SHIFT + D` + </TabItem> + <TabItem label="Linux"> + * Start a new conversation: `CTRL + SHIFT + N` + * Open a new tab: `CTRL + SHIFT + T` + * Open a new pane: `CTRL + SHIFT + D` + </TabItem> +</Tabs> + +## Conversation Panel + +The **Conversation Panel** on the left side of the window is the home for browsing and switching between agent conversations. It's designed to make multi-threaded work obvious: you can see what's active, what you ran recently, and jump back into any thread without guessing where your context went. + +![Conversation Panel listing active and past agent conversations.](../../../../../assets/agent-platform/agent-conversations-new-modality.png) + +### Panel layout + +The conversation panel is split into two dropdowns (collapsible sections) that help you navigate between conversations: + +#### Active + +The **Active** dropdown lists conversations where you have sent at least one query since opening them. Simply expanding a conversation does not make it active—you need to interact with the Agent first. + +* Select a conversation to switch to it immediately. +* The conversation you're currently viewing is highlighted. +* Cloud agent conversations and Oz runs always appear in **Active** while they are open. + +#### Past + +The **Past** dropdown lists your recent conversation history. + +Each row typically shows: + +* Conversation title +* When it happened (for example, "8 min ago", "3 days ago") +* Working directory (when relevant) + +Use **Past** to restore a previous conversation. When you select a past conversation, Warp reopens it in a new tab or your active pane, letting you continue where you left off. + +### Conversation storage + +By default, your agent conversations are stored locally on your machine. You can optionally enable **cloud-synced conversations** to: + +* Access your conversation history across different devices +* Share conversations with teammates +* Retain conversations when you log out or switch machines + +For full details on enabling cloud sync, sharing conversations, and accessing cloud agent conversations, see [Cloud-synced Conversations](/agent-platform/local-agents/cloud-conversations/). + +:::note +To enable cloud sync, go to **Settings** > **Privacy** and toggle on **"Store AI conversations in the cloud"**. When disabled, conversations are stored locally only and cannot be shared. Note that cloud agent conversations are always stored in the cloud regardless of this setting. +::: + +### Search + +Use the search field at the top of the conversation panel to quickly find your conversation. + +* Type to filter conversations by title (and, in some builds, by directory/context). +* Useful when you have many threads and want to jump directly to one. + +### New conversation + +Click the **New conversation** button at the bottom of the **Active** conversation list to start a new conversation. + +Starting a new conversation creates a fresh thread in the **Active** dropdown, without deleting or overwriting your previous ones. + +### Navigation behavior + +Navigation between [Terminal and Agent modes](/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes/) is designed to be direct: + +* **Clicking an active conversation** - Takes you directly to that conversation view. +* **Clicking a past conversation** - Opens the conversation in a **new pane**, preserving your current context. +* **Command Palette** - Open the Command Palette and type `conversations:` to filter and navigate directly to any conversation. +* **`⌘Y` conversation selector** - Opens a dedicated menu showing your existing and past conversations. This works in both terminal view and agent view. +* **Up-arrow history** - Shows both past shell commands and past prompts you've sent in recent conversations. The behavior differs by context: + * **In terminal view** - Shows both past shell commands and recent conversations. + * **In agent view** - Shows past prompts you've sent in conversations. + +--- + +### Ways to move around + +Use `esc` or the back button to return to terminal mode, `⌘Y` to open the conversation selector, or `⌘↩` to start a new conversation. For a complete list of keyboard shortcuts and slash commands, see [Terminal and Agent modes - Keyboard shortcuts](/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes/#keyboard-shortcuts-quick-reference). + +### Exit confirmation for in-progress conversations + +Exiting a conversation that is still in progress will **cancel** the agent's current work. To prevent accidental cancellations, Warp shows a confirmation hint: + +* **First exit attempt** - The hint changes to "Press again to exit" (or similar). +* **Confirmation window** - You have about 2 seconds to press `esc` or `^C` again to confirm. +* **After confirmation** - Warp exits the conversation and cancels the in-progress request. + +This confirmation step ensures you don't accidentally lose work when the agent is mid-task. + +:::note +Empty new conversations (where you haven't sent any messages yet) can be exited immediately without confirmation. +::: diff --git a/src/content/docs/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes.mdx b/src/content/docs/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes.mdx new file mode 100644 index 0000000..988d880 --- /dev/null +++ b/src/content/docs/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes.mdx @@ -0,0 +1,378 @@ +--- +title: Terminal and Agent modes +description: >- + Warp provides two distinct modes: a clean terminal for commands, and a + dedicated conversation view for multi-turn agent workflows. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Warp provides two distinct modes: a clean terminal for commands, and a dedicated conversation view for multi-turn conversations with [Oz, Warp's agent](/agent-platform/local-agents/interacting-with-agents/). + +<VideoEmbed url="https://youtu.be/J715YW5VC18" /> + +--- + +## Key terminology + +Before diving in, here are two key concepts: + +* **Terminal session** - Your shell environment where you run commands. This is the default mode when you open Warp—a clean, traditional terminal input. +* **Oz agent conversation** - A multi-turn interaction with Oz. Conversations maintain context across exchanges and have their own dedicated view with richer controls. + +Terminal and Agent modes make switching between these two contexts seamless while keeping them visually distinct. + +--- + +## Why two modes + +Terminal and Agent modes separate your terminal and agent workflows into distinct contexts: + +* **Clean terminal by default** - Minimal input when you're running commands. Agent controls appear only when you need them. +* **Dedicated conversation view** - Multi-turn agent workflow spaces have full controls like model select, voice input, image attachments, and conversation history. +* **Explicit mode switching** - The current mode is clearly visible, enabling better workflow organization—you can separate, minimize, and expand different conversations. + +--- + +## Two distinct modes + +### Terminal mode (default) + +Terminal mode is the default when you open a new tab or pane. + +* Looks and behaves like a traditional terminal input. +* Agent controls are not always visible, keeping the interface clean. +* A message bar shows contextual hints for interacting with agents. + +![Default terminal mode in Warp, showing a clean terminal input.](../../../../../assets/agent-platform/terminal-modality.png) + +**Terminal mode hints** + +The message bar at the bottom of the terminal provides contextual guidance: + +* **Default hint** - Shows `⌘↩ for new agent` when the input is empty. +* **Send to agent** - Shows `⌘↩ to send to agent` when you have text that could be a prompt. +* **Error block attachment** - When the last command failed, shows a hint to attach the output as agent context (e.g., `⌘↑ attach 'npm install...' output as agent context`). +* **Attached context indicator** - Shows when you have blocks or text selections attached (e.g., `⌘↩ to send to agent with 'git status' attached`). +* **Continue conversation** - When your last visible item is an agent conversation block, shows `⌘Y to continue conversation`. + +If auto-detection is enabled, Warp labels your input as "agent" or "shell" before you submit, showing "(autodetected)" in magenta. See [Understanding auto-detection](#understanding-auto-detection) for configuration and override methods. + +**Disabling the message bar:** To hide the terminal mode hint bar while keeping AI features enabled, go to **Settings** > **Features** > **Terminal Input** and toggle off **Show terminal input message line**. This only hides the contextual hints—it does not disable any AI functionality. + +:::caution +If you disable the message bar while auto-detection is enabled, you won't see the visual indicator that tells you whether Warp detected your input as a shell command or an agent prompt. Consider also disabling auto-detection (**Settings** > **Agents** > **Warp Agent** > **Input**) if you turn off the message bar. +::: + +:::note +The shortcuts shown on this page use macOS keybindings. For Windows and Linux shortcuts, see [Keyboard Shortcuts](/getting-started/keyboard-shortcuts/). +::: + +### Oz agent conversation view (expanded UI) + +* A dedicated conversation view with richer agent controls including model select, voice input, image attachments, and conversation management. +* Familiar "charms" (current directory, git branch, diff view entry point, etc.) are still available. +* Designed for multi-turn workflows and managing multiple conversations. + +![The dedicated Agent Conversation View.](../../../../../assets/agent-platform/agent-modality-conversation-view.png) + +**Key difference** + +Agent controls appear only when you're in a conversation, keeping your terminal clean otherwise. + +In the previous UI, agent controls were always present. With Terminal and Agent modes, these controls are hidden by default and appear **once you enter an agent conversation.** + +:::note +Agent conversation views are identified with an alternative background color and the input toolbelt showing model selector, voice input, and image attachment buttons. +::: + +#### Customizing the input toolbelt + +The chips and buttons on the agent input toolbelt can be reordered, hidden, or moved between the left and right sides of the input. Right-click the input in an agent conversation and select **Edit agent toolbelt** to open the editor. Your layout persists across app restarts. + +Agent Mode-specific items include the model selector, autodetection toggle, Context Usage, and fast forward toggle. Shared items like voice input, file attachment, and context chips appear in both the Agent Mode toolbelt and the [CLI coding agent toolbelt](/agent-platform/cli-agents/overview/#customizing-the-toolbelt). + +**Block origin and visibility** + +Blocks in Warp belong to either the terminal view or a specific agent conversation: + +* **Terminal blocks** - Commands you run directly in the terminal always appear in your terminal blocklist and can be attached as context to any conversation. +* **Agent conversation blocks** - Commands executed within an agent conversation (either by you or the agent) only appear within that specific conversation and don't appear in the terminal blocklist. + +In agent conversations, context is managed automatically, with optional manual attachment from terminal view: + +* **Automatic context** - Commands executed within an agent conversation are included as context for subsequent prompts. +* **Manual attachment** - You can attach terminal blocks to bring in outputs from outside the conversation. +* **Conversation scope** - Agent conversation blocks stay scoped to that conversation, while terminal blocks remain in the terminal blocklist. + +This separation keeps your terminal view clean while preserving full context within each conversation. For shortcuts, pending vs. attached context, and block selection behavior, see [Blocks as Context](/agent-platform/local-agents/agent-context/blocks-as-context/). + +#### Cloud agent conversations + +In addition to local agent conversations, you can start **Oz cloud agent conversations** that run in an isolated cloud environment. Cloud agents are useful for: + +* Running parallel agents across multiple tasks +* Running agents remotely on hosted computers (offloading compute from your local machine) +* Running agents autonomously in the cloud +* Checking in on your agents from anywhere + +To start a cloud agent conversation, press `⌥⌘↩` (Option+Command+Enter on macOS, or `Ctrl+Alt+Enter` on Windows/Linux) from terminal mode. You can also use the welcome block's "Start cloud project" action. + +Cloud agent conversations have a few differences from local conversations: + +* **Environment selector** - Choose which [Warp Environment](/agent-platform/cloud-agents/environments/) to run in +* **Credits indicator** - Shows your remaining cloud agent credits +* **Different zero state** - The conversation header indicates "New Oz cloud agent conversation" + +Cloud agent conversations are always stored in the cloud. For more details on accessing and sharing cloud conversations, see [Cloud-synced Conversations](/agent-platform/local-agents/cloud-conversations/). + +**Accessing running or past cloud conversations:** + +* **From the conversation list panel** - Cloud conversations appear alongside local conversations. Click to open. +* **From the management view** - Use the [Agent Management view](/agent-platform/cloud-agents/managing-cloud-agents/) to see all cloud agent runs, filter by status, and click any row to open the conversation. +* **From the Oz web app** - Access your cloud agents at [oz.warp.dev](https://oz.warp.dev) to manage runs from any browser. + +For more on cloud agents, see [Cloud Agents Overview](/agent-platform/cloud-agents/overview/). + +--- + +## Understanding auto-detection + +Auto-detection (which detects whether you're typing natural language or a shell command) helps Warp interpret each input as either a shell command or an agent request. When auto-detection is enabled, Warp shows an **inline indicator** in the prompt (for example, "(autodetected)" in magenta). + +![Inline "(autodetected)" indicator showing Warp routed terminal input to the agent.](../../../../../assets/agent-platform/send-to-agent.png) + +### How it works + +**In terminal mode:** + +When you type text that appears to be a natural language request (e.g., "Summarize the dependencies in this project"), Warp labels it as "agent" and displays the "(autodetected)" indicator. Pressing Enter will send your input directly to the agent in a new conversation, creating a "quicksend" workflow for text-only requests. + +**In agent conversation view:** + +When auto-detection identifies your input as a shell command, Warp displays a distinct UI border around the input to indicate the mode switch. This helps you understand that your input will run as a command rather than being sent to the agent. + +### Settings + +:::note +You can control auto-detection separately for terminal mode and agent conversation view. Both toggles are in **Settings** > **Agents** > **Warp Agent** > **Input**: + +* **Terminal mode:** Toggle **Autodetect agent prompts in terminal input** +* **Agent conversation view:** Toggle **Autodetect terminal commands in agent input** +::: + +### Override methods + +There are multiple ways to override auto-detection: + +* **Keyboard shortcut** - Press `⌘I` to switch between command and Agent Mode. +* **`!` prefix** - In agent view, prepend `!` to your input to force it to run as a shell command (e.g., `!ls` or `!git status`). + +Common examples: + +* You typed something that looks like a command, but you intended an agent request. +* You typed a sentence, but you intended it to run as a command (rare, but it happens). + +:::note +**Note:** After you override, the selection is "sticky" for that entry, so you can submit confidently. +::: + +### Defaults for new vs existing users + +Auto-detection is enabled by default for new Warp users. For users who had Warp before Terminal and Agent modes were introduced, auto-detection is disabled by default to preserve their existing workflows. + +--- + +## Entering and navigating conversations + +### How to enter a conversation + +There are several ways to start or enter an Oz agent conversation: + +#### A) Use the `/agent` or `/new` slash command + +Type `/agent` or `/new` in terminal mode to enter the agent conversation view. This is the recommended way to explicitly switch to Agent Mode. + +* `/agent` or `/new` - Opens a new agent conversation view with full controls +* `/agent <prompt>` - Sends your prompt directly to the agent in a new conversation + +#### B) Use the keyboard shortcut + +Press `⌘↩` (Command+Enter on macOS, or `Ctrl+Shift+Enter` on Windows/Linux) to enter the conversation view immediately. This is a shortcut for `/agent`. + +**Use this when you want to:** + +* attach an image +* use voice input +* access other conversation-only controls before sending your first message + +#### C) Quicksend with auto-detection + +When auto-detection is enabled in terminal mode, you can start a conversation immediately: + +1. Type a natural language request (e.g., "Summarize the dependencies in this project"). +2. If Warp detects it as an agent request, it shows an "(autodetected)" indicator. +3. Press Enter to send directly to the agent in a new conversation. + +This "quicksend" method is useful for quick, text-only requests when you don't need conversation-only controls like voice input or image attachments. + +#### D) Continue from the up-arrow history menu + +Press `↑` (up arrow) to open an inline history menu. The menu contents vary by context—see [Navigation behavior](/agent-platform/local-agents/interacting-with-agents/#navigation-behavior) for details on how up-arrow works in terminal view vs. agent view. + +#### E) Click an active AI suggestion + +When [Active AI Recommendations](/agent-platform/local-agents/active-ai/) is enabled, Warp displays contextual prompt suggestions based on your recent activity. Clicking any of these suggestions opens the agent conversation view and sends that prompt immediately. + +--- + +### Navigating conversations + +Warp includes a **Conversation Panel** for browsing and managing your agent conversations. For details on the panel layout, navigation, and conversation storage, see [Agent Conversations](/agent-platform/local-agents/interacting-with-agents/). + +### Using slash commands + +**In an agent conversation** + +![Slash command menu open inside an agent conversation, showing the full set of commands.](../../../../../assets/agent-platform/slash-commands-agent-modality.png) + +While you're in an agent conversation, you can access Warp's [slash commands](/agent-platform/capabilities/slash-commands/) any time by typing `/` in the input. + +* Type `/` to open the command menu +* Keep typing to filter commands (for example: `/conversations`, `/compact`) +* Use `↑` / `↓` to navigate and `Enter` to run +* Press `esc` to dismiss the menu + +**Key slash commands in Agent Mode:** + +* `/new` or `/agent` - Start a new conversation. +* `/plan` or `/plan <prompt>` - Enter agent view and start a planning conversation. The agent will create an implementation plan before making changes. +* `/conversations` - Open the conversation list panel. +* `/compact` - Summarize and compact the current conversation to free up context window space. +* `/fork` - Fork the current conversation into a new thread. Press `Enter` to fork in the existing pane, or `⌘↩` (`Ctrl+Shift+Enter` on Windows/Linux) to fork in a new pane. +* `/fork-and-compact` - Fork the conversation and automatically summarize it. +* `/fork from` - Choose a specific point in the conversation to fork from. A menu appears showing your previous queries—select one to fork from that point. +* `/model` - Select or change the AI model for the conversation. + +Slash commands are a quick way to take common actions without leaving the keyboard. + +**In terminal mode** + +![Slash command menu open from terminal mode, showing a reduced set of quick actions.](../../../../../assets/agent-platform/slash-commands-terminal-modality.png) + +Slash commands aren't just for agent conversations. You can also type `/` in terminal mode to open a limited set of commands. + +:::note +Agent conversations expose the full set of slash commands (including `/fork`, `/compact`, and `/model`). Terminal mode exposes a reduced set focused on quick actions. +::: + +For the complete list of available slash commands, see [Slash Commands](/agent-platform/capabilities/slash-commands/). + +### Forking conversations + +Forking lets you branch off from an existing conversation to explore a different direction without losing your original thread. + +**How to fork:** + +1. In an agent conversation, type `/fork` and press `Enter`. +2. Choose where to open the forked conversation: + * `Enter` - Fork in the current pane (replaces the current view). + * `⌘↩` (`Ctrl+Shift+Enter` on Windows/Linux) - Fork in a new pane (keeps the original visible). + +**Fork and compact:** + +Use `/fork-and-compact` to fork and automatically summarize the conversation. This is useful when your context window is getting full but you want to continue building on the same work. + +**Fork from a specific point:** + +Use `/fork from` to choose exactly where in the conversation you want to branch from: + +1. Type `/fork from` and press `Enter`. +2. A menu shows your previous queries in the conversation. +3. Select the query you want to fork from. +4. Choose `Enter` (existing pane) or `⌘↩` / `Ctrl+Shift+Enter` (new pane). + +This is helpful when you want to go back to an earlier point and try a different approach. + +For more forking methods and use cases, see [Conversation Forking](/agent-platform/local-agents/interacting-with-agents/conversation-forking/). + +--- + +## Using Agent Mode as the default experience + +If you prefer to type natural language at any point in a terminal session and have it automatically routed to an agent, you can configure this using the "default mode for new sessions" setting. + +![Using Agent as your default for new tab sessions](/assets/agent-platform/recreate-universal-input.gif) + +### Step 1 — Set new tabs to open in agent view + +By default, new tabs and panes open in terminal mode. To launch directly into an Oz agent conversation instead: + +1. Go to **Settings** > **Features** > **General**. +2. Change **Default mode for new sessions** to **Agent**. + +### Step 2 — Enable auto-detection in Agent Mode + +With auto-detection enabled in agent view, Warp automatically detects whether your input is natural language or a shell command, routing it to the agent or running it in the terminal accordingly. + +You can also use the "toggle input mode" keyboard shortcut to override auto-detection and force either "shell" or "agent" mode. + +1. Go to **Settings** > **Agents** > **Warp Agent** > **Input**. +2. Toggle on **Autodetect terminal commands in agent input**. + +Press `⌘I` (macOS) or `Ctrl+I` (Windows/Linux) to manually toggle between shell and Agent Mode at any time, overriding auto-detection. + +:::note +Auto-detection is enabled by default for new Warp users. +::: + +--- + +## Keyboard shortcuts (quick reference) + +In conversation view, press `?` to show/hide the full shortcuts panel. Here are the key shortcuts: + +### Navigation and mode switching + +* **Start new agent conversation** (from terminal mode) - `⌘↩` (macOS) / `Ctrl+Shift+Enter` (Windows/Linux) +* **Start new cloud agent conversation** (from terminal mode) - `⌥⌘↩` (macOS) / `Ctrl+Alt+Enter` (Windows/Linux) +* **Send to agent with attached context** (from terminal mode) - `⌘↩` (macOS) / `Ctrl+Shift+Enter` (Windows/Linux) when blocks are selected +* **Tag agent into long-running command** - `⌘↩` (macOS) / `Ctrl+Shift+Enter` (Windows/Linux) while an interactive command is running +* **Exit conversation** (back to terminal mode) - `esc` +* **Stop agent / exit on empty input** - `^C` / `Ctrl+C` +* **Open conversation selector** - `⌘Y` (macOS) / `Ctrl+Y` (Windows/Linux) +* **Toggle conversation list panel** - `⌘⇧H` (macOS) / `Ctrl+Shift+H` (Windows/Linux) +* **Override auto-detection** (switch shell ↔ agent) - `⌘I` (macOS) / `Ctrl+I` (Windows/Linux) + +### Input modifiers + +* **`!`** - Prepend to force shell mode (e.g., `!ls`) +* **`/`** - Open slash command menu +* **`@`** - Open context menu (attach files, symbols, etc.) +* **`?`** - Show/hide keyboard shortcuts panel + +### Conversation actions + +* **Resume a paused/cancelled conversation** - `⌘⇧R` (macOS) / `Ctrl+Alt+R` (Windows/Linux) +* **Toggle auto-accept** (for agent tool executions) - `⌘⇧I` (macOS) / `Ctrl+Shift+I` (Windows/Linux) +* **Open code review pane** - `⌘⇧+` (macOS) / `Ctrl+Shift++` (Windows/Linux) +* **Toggle plan panel** (if a plan exists) - `⌘⌥P` (macOS) / `Ctrl+Alt+P` (Windows/Linux) + +### In slash command / fork menus + +* **Navigate menu items** - `↑` / `↓` +* **Select** (fork in existing pane) - `Enter` +* **Select and open in new pane** - `⌘↩` (macOS) / `Ctrl+Shift+Enter` (Windows/Linux) +* **Dismiss menu** - `esc` + +### Customizing keybindings + +You can customize keyboard shortcuts for slash commands and other actions in **Settings** > **Keyboard shortcuts**. This lets you assign your preferred key combinations to frequently used commands. + +For example, to bind a keyboard shortcut to the `/agent` slash command: + +1. Open **Settings** > **Keyboard shortcuts** +2. Search for "agent" or the slash command you want to bind +3. Click the shortcut field and press your desired key combination +4. The shortcut is saved automatically + +This is useful for actions you perform frequently, like starting a new conversation or opening the conversation list. diff --git a/src/content/docs/agent-platform/local-agents/interacting-with-agents/voice.mdx b/src/content/docs/agent-platform/local-agents/interacting-with-agents/voice.mdx new file mode 100644 index 0000000..b2fdaed --- /dev/null +++ b/src/content/docs/agent-platform/local-agents/interacting-with-agents/voice.mdx @@ -0,0 +1,84 @@ +--- +title: Voice +description: >- + Voice enables natural language interaction with Warp, letting you speak + commands and queries directly to your terminal. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +Warp's Voice feature transforms how you interact with your terminal, letting you naturally speak commands and questions instead of typing them. This is especially powerful when combined with Agent Mode for complex operations or when you need to explain longer scenarios. + +:::note +Voice input functionality can be configured in **Settings** > **Agents** > **Warp Agent** > **Voice**. You can toggle voice input and select your preferred activation hotkey from pre-defined options. +::: + +<VideoEmbed url="https://www.loom.com/share/77399be4e434443488bbe267b3548552?hideEmbedTopBar=true&hide_owner=true&hide_share=true&hide_title=true" title="Voice Demo" /> + +## Getting started with voice + +### Initial setup + +First-time users will need to grant microphone permissions: + +* On macOS: Accept the system permission prompt or allow Warp microphone access in  > **System Settings** > **Privacy & Security** > **Microphone** +* On Windows: Allow Warp microphone access in **Settings** > **Privacy & Security** > **Microphone** +* On Linux: Configure through system sound settings + +### Using voice + +There are two ways to activate Voice: + +1. **Microphone Button in Agent Mode** + * Click the microphone icon in Agent Mode + * Start speaking when the indicator shows it's listening + * Click again to stop recording +2. **Hotkey Method** + +<Tabs> + <TabItem label="macOS"> + * Press and hold the `Fn` key (configurable) to start recording + * Speak your command or query while holding the key + * Release the `Fn` key to stop recording and transcribe + </TabItem> + <TabItem label="Windows"> + * Press and hold the `ALT-RIGHT` key (configurable) to start recording + * Speak your command or query while holding the key + * Release the `ALT-RIGHT` key to stop recording and transcribe + </TabItem> + <TabItem label="Linux"> + * Press and hold the `ALT-RIGHT` key (configurable) to start recording + * Speak your command or query while holding the key + * Release the `ALT-RIGHT` key to stop recording and transcribe + </TabItem> +</Tabs> + +![Voice settings panel showing hotkey configuration and voice input toggle options](../../../../../assets/agent-platform/voice-settings.png) + +### Sample use cases + +Voice input makes complex interactions with Agent Mode more natural and efficient. Instead of typing lengthy queries, you can speak naturally to accomplish various tasks. For example, you can say "Create a new Node.js project, install Express and MongoDB, then set up a basic server with a health check endpoint," or "What's the difference between chmod and chown? Give me examples of when to use each one." + +You can also describe multi-step system tasks like "Find all log files in my project that contain errors from the last 24 hours, create a summary of the errors, and email it to me." Agent Mode breaks down these requests into the necessary commands and provides detailed explanations. + +Voice input is not limited to just Agent Mode - it works across all of Warp's input interfaces. Whether you're using the Find dialog to search through text, entering commands in the terminal, or working with other input editors, you can use voice commands to quickly input your text. + +![Voice input works across Warp's editor interfaces, including the Find dialog and other input editors](../../../../../assets/agent-platform/voice-in-find.png) + +## Privacy & security + +The transcription is powered by [Wispr Flow](https://wisprflow.ai/). Voice data is processed in real-time by Wispr Flow and is not retained as a recording after transcription. + +## Usage limits + +Voice features have anti-abuse limits in place to ensure fair usage. These limits are subject to change as we continue to improve the service. + +## Troubleshooting + +### Common issues + +1. **Microphone not detected** If your microphone isn't being detected, first check your system permissions to ensure Warp has access. You should also verify that your microphone is properly connected to your system. If issues persist, try restarting Warp to reset the connection. +2. **Poor transcription quality** To improve transcription quality, try to minimize background noise in your environment. Position yourself closer to the microphone while speaking, and verify that your microphone input levels are properly adjusted in your system settings. For best results, speak clearly at a natural pace and use complete sentences to provide better context. When referring to specific file names or commands, enunciate them clearly. It's also recommended to review the transcription before sending to ensure accuracy. +3. **Feature not activating** If the Voice feature isn't activating, confirm that your hotkey settings are correctly configured in Warp. Check for any conflicting keyboard shortcuts that might interfere with Voice activation. Also ensure that you're running the latest version of Warp, as older versions can have compatibility issues. + + If you are on an Enterprise plan, your administrator may have disabled Voice functionality, or it may be pending approval. diff --git a/src/content/docs/agent-platform/local-agents/interactive-code-review.mdx b/src/content/docs/agent-platform/local-agents/interactive-code-review.mdx new file mode 100644 index 0000000..e1acd96 --- /dev/null +++ b/src/content/docs/agent-platform/local-agents/interactive-code-review.mdx @@ -0,0 +1,74 @@ +--- +title: Interactive Code Review +description: >- + Review agent-generated code, leave inline comments, and have Warp's native + agent or any supported third-party CLI agent apply your feedback. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +### Overview + +Interactive Code Review lets you review, annotate, and refine code generated by any supported agent, whether that's Warp's native Agent or a third-party CLI agent running in Warp. Instead of relying on an AI to review another AI's output, Warp keeps the developer in control. + +You can inspect diffs, leave inline comments, batch feedback, and send all requested changes back to the agent in a single pass. + +<VideoEmbed url="https://youtu.be/jit_6eevt8w?si=EFKYUSsofvBYUPI-" /> + +**Interactive Code Review builds on Warp's existing** [Code Review](/code/code-review/) **panel.** For details on diff views, reverting hunks, opening files, and all available entry points, see the Code Review documentation. + +:::note +Note that both the [Code Review](/code/code-review/) panel and Interactive Code Review require working in a Git-indexed directory. +::: + +### Supported agents + +Interactive Code Review works with any supported agent running in Warp: + +* **Warp's native Agent** — the built-in agent in Agent Mode +* **Third-party CLI agents** — Claude Code, OpenAI Codex, OpenCode, Amp, Auggie, Copilot CLI, Cursor CLI, Gemini CLI, Droid, and Pi + +For the full feature matrix and setup details for each CLI agent, see [Third-Party CLI Agents](/agent-platform/cli-agents/overview/). + +--- + +When an agent modifies files, Warp automatically gathers those edits into a diff. Opening the Code Review panel shows you every change the agent made. + +From there, you can leave comments on specific lines or blocks, review your comment list, and submit all feedback to the agent at once. The agent applies the requested updates and returns an updated diff for further review. + +This gives you a familiar pull-request style workflow inside Warp without switching editors or tools. + +### Leave inline comments + +Select any changed line or block and add a comment describing what you want adjusted. Warp anchors each comment to the relevant file and line so the agent understands exactly what to fix. + +![Adding an inline comment on a changed line in the Code Review panel.](../../../../assets/agent-platform/interactive-code-review-adding-comment.png) + +### Batch comments and submit once + +Add as many comments as you need before submitting them. The agent receives your entire batch of feedback, applies the changes in one iteration, and returns an updated diff for verification. + +![Adding comments directly in the Code Review view.](../../../../assets/agent-platform/interactive-code-review-batch-comments.png) + +### Example demo + +In the example from Kevin on the Warp team, you’ll see how to: + +* open the Code Review panel after an agent produces changes +* browse the diffs for each edited file +* add multiple inline comments +* review all comments in the list view +* send those comments to the agent for resolution +* inspect the updated diffs once the agent applies the changes + +This workflow can be repeated until the code matches your expectations. + +<VideoEmbed url="https://www.loom.com/share/bdeb2eb1ff3640faa2cbacda9420c3a8" /> + +--- + +## Next steps + +Once you're comfortable reviewing agent code locally, try running agents in the cloud for longer or parallel tasks. + +* **[Cloud Agents quickstart](/agent-platform/cloud-agents/quickstart/)** - Run agents on Warp's infrastructure for background tasks like PR review, issue triage, and dependency updates. +* **[Skills](/agent-platform/capabilities/skills/)** - Turn successful agent workflows into reusable, shareable instructions. diff --git a/src/content/docs/agent-platform/local-agents/overview.mdx b/src/content/docs/agent-platform/local-agents/overview.mdx new file mode 100644 index 0000000..5193229 --- /dev/null +++ b/src/content/docs/agent-platform/local-agents/overview.mdx @@ -0,0 +1,36 @@ +--- +title: Warp Agents overview +description: >- + Powerful AI features like agents, code review, voice, and active AI + recommendations, fully integrated into the Warp Agentic Development + Environment. +--- + +## AI in Warp + +Warp includes intelligent Oz agents designed to help you build, test, deploy, and debug while keeping you in control. Interactive agent conversations in Warp can look up commands, execute tasks, fix bugs, and adapt to your workflows. You can manage agent behavior directly, with full context from your Warp Drive and your team. + +:::note +Warp's AI features can be globally disabled in **Settings** > **Agents** > **Warp Agent** with the AI toggle.\ +\ +These features send input data to various LLM providers through their API. Warp is **SOC 2 compliant** and has **Zero Data Retention** policies with all contracted LLM providers — no customer AI data is retained, stored, or used for training. Read more about data privacy for Warp features [on our privacy page](https://www.warp.dev/privacy). +::: + +Warp's client is open source under [AGPL v3](https://github.com/warpdotdev/warp/blob/master/LICENSE) at [`warpdotdev/warp`](https://github.com/warpdotdev/warp). The agent surface you're reading about is built in the open — see [Contributing to Warp](/support-and-community/community/contributing/) to read the code, file issues, or shape the roadmap. + +## What you can do with agents + +This section covers how to interact with Warp's agents and the capabilities available during agent conversations: + +* [Interacting with Agents](/agent-platform/local-agents/interacting-with-agents/) - Manage AI conversations tied to sessions, attach context, continue previous threads, or start new ones. +* [Agent Context](/agent-platform/local-agents/agent-context/) - Attach images, URLs, files, code blocks, and selections as context for your prompts. +* [Model Choice](/agent-platform/capabilities/model-choice/) - Pick your preferred LLM from a curated set of top models, or let Warp choose the optimal one. +* [Full Terminal Use](/agent-platform/capabilities/full-terminal-use/) - Let the agent drive interactive terminal apps, seeing live output and running commands. +* [Interactive Code Review](/agent-platform/local-agents/interactive-code-review/) - Review agent-generated diffs, leave inline comments, and have the agent address your feedback. +* [Task Lists](/agent-platform/capabilities/task-lists/) - Track complex workflows with automatic task lists that update progress in real time. +* [Web Search](/agent-platform/capabilities/web-search/) - Allow agents to search the web for up-to-date information. +* [Third-Party CLI Agents](/agent-platform/cli-agents/overview/) - Run third-party CLI agents like Claude Code and Codex with Warp's built-in agent toolbelt. +* [Active AI Recommendations](/agent-platform/local-agents/active-ai/) - Get proactive fix recommendations based on errors and outputs. +* [Voice](/agent-platform/local-agents/interacting-with-agents/voice/) - Talk to Warp's agent using voice commands. + +For foundational capabilities like planning, rules, MCP servers, and agent profiles, see [Capabilities](/agent-platform/capabilities/). diff --git a/src/content/docs/agent-platform/local-agents/session-sharing.mdx b/src/content/docs/agent-platform/local-agents/session-sharing.mdx new file mode 100644 index 0000000..5d26b68 --- /dev/null +++ b/src/content/docs/agent-platform/local-agents/session-sharing.mdx @@ -0,0 +1,86 @@ +--- +title: Agent Session Sharing +description: >- + Share live agent sessions so collaborators can view, steer, and interact + with agent activity from any device — in real time or asynchronously. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +**Agent Session Sharing** extends Warp's regular [Session Sharing](/knowledge-and-collaboration/session-sharing/) to include full visibility and control over Agent activity. Share any agent session — Oz or third-party — so collaborators can watch progress, review output, and steer the agent from the Warp desktop app, a web browser, or a mobile device. + +<VideoEmbed url="https://www.loom.com/share/89e0e99c9bbf463a8a5e5bc2e96dabe4" title="Agent Session Sharing in action — sharing a live session and collaborating across devices." /> + +## Key capabilities + +* **Full Agent visibility** - Viewers see Agent prompts, responses, thinking states, tool use, planning steps, and [credit](/support-and-community/plans-and-billing/credits/) consumption in real time +* **Cross-device access** - Open shared sessions from the Warp desktop app, any web browser, or a mobile device. No install required for web viewers. +* **Collaborative editing** - Grant edit access so collaborators can send their own Agent queries, execute commands, and start new conversations +* **Multi-viewer support** - Multiple participants can observe and interact with the same session simultaneously, each with their own cursor and avatar +* **Remote Control** - Publish third-party agent sessions to the cloud for persistent, asynchronous monitoring and steering from anywhere. See [Remote Control](/agent-platform/cli-agents/remote-control/). + +## How it works + +When you share an agent session, Warp publishes it to the cloud and generates a shareable link. The session stays in sync — any new agent output or terminal activity appears for all viewers in real time. The person who shares the session controls who can view and who can interact. + +## Sharing a session + +1. Start or open an agent session in Warp. The agent can be an Oz agent, a third-party coding agent, or any interactive agent running in your terminal. +2. Open the share action from any of these entry points: + * **Command Palette** - Search for "Share session" + * **Pane header** - Click the overflow menu in the pane header + * **Right-click context menu** - Right-click inside the session pane + * **`/remote-control` chip** - For third-party agent sessions, click the `/remote-control` chip in the agent view footer or the CLI footer to publish and share instantly. See [Remote Control](/agent-platform/cli-agents/remote-control/) for details. +3. Choose your starting point (full scrollback, no scrollback, or a specific block). +4. Confirm the share. Warp uploads the session to the cloud and generates a shareable link. +5. Copy the link and share it with teammates, or open it on another device. + +![Starting a shared agent session from the right-click context menu](../../../../assets/agent-platform/agent-session-sharing-right-click-menu.png) + +![Starting a shared agent session from the Command Palette](../../../../assets/agent-platform/agent-session-sharing-command-palette.png) + +## Viewing shared sessions + +Shared sessions are accessible from: + +* **Warp desktop app** - Paste the link into Warp on a different machine for the full desktop experience +* **Web browser** - Open the shared link in any browser. No app install required. +* **Mobile** - Open the link on a phone or tablet browser to check on progress while away from your desk + +The web experience mirrors the desktop view, showing complete Agent activity including thinking steps, tool use, and terminal output. + +## Collaboration and steering + +### Watching Agent activity + +Viewers see Agent actions unfold live as the sharer interacts with the Agent: + +* **Thinking animations** - Real-time indicators of Agent reasoning +* **Tool use and planning** - Visible tool calls and planning steps +* **Credit consumption** - Live credit usage for the session +* **Final responses** - Completed Agent output + +### Edit access + +If a viewer requests edit access, the sharer can approve it. Once approved, collaborators can: + +* Send new Agent queries +* Type directly into the prompt +* Execute commands +* Start and switch Agent conversations +* Run terminal commands alongside Agent queries + +### Multi-viewer sessions + +Multiple participants can join the same session from different machines, browsers, or environments. All participants: + +* See each other's avatars and cursors +* Watch Agent activity in sync +* Edit together when granted access +* Run terminal or Agent commands concurrently + +## Related pages + +* [Remote Control](/agent-platform/cli-agents/remote-control/) +* [Third-Party CLI Agents](/agent-platform/cli-agents/overview/) +* [Cloud Agent Session Sharing](/agent-platform/cloud-agents/viewing-cloud-agent-runs/) +* [Session Sharing (terminal)](/knowledge-and-collaboration/session-sharing/) diff --git a/src/content/docs/changelog/index.mdx b/src/content/docs/changelog/index.mdx new file mode 100644 index 0000000..c49dd13 --- /dev/null +++ b/src/content/docs/changelog/index.mdx @@ -0,0 +1,3950 @@ +--- +title: Changelog +description: >- + Warp auto-updates whenever a new release comes out. We try to ship an update + every week usually on Thursday! +--- + +Submit bugs and feature requests on our [GitHub board!](https://github.com/warpdotdev/Warp/issues/new/choose) + +### 2026.04.22 (v0.2026.04.22.08.46) + +**New features** + +* Toolbar chips can now be rearranged by right-clicking anywhere in the top bar and selecting "Rearrange toolbar items". +* Mermaid diagrams now render in markdown notebooks. + +**Improvements** + +* Added support for pasting images into the rich input editor with CLI agents, such as Claude Code or Codex. +* Typing `_text_` or `__text__` in a code review or rich-text comment now renders as italic or bold, matching the existing `*text*`/`**text**` behavior. +* \[Windows] Added a "Start Warp at login" toggle under **Settings** > **Features** > **General** that registers Warp to launch automatically when you sign in to Windows. +* Add View menu entries (with keyboard shortcuts) for the Global Search and Agent Conversations left panel items on macOS. +* \[Windows] Added 408 new PowerShell cmdlet completions and improved suggestion quality for existing PowerShell completions. +* Added completions for `pprof`. +* `/fork` now opens the forked conversation in a new pane with Enter and in a new tab with Cmd+Enter. +* Right-click a URL or file-path link inside an AI response to copy it directly via the context menu. +* Added a setting to hide the lines added/removed counts from the code review button in the tab bar. +* Reorganized settings into subpages for Agents, Code, and Cloud platform; improved settings search. +* Wired branch completion into `git log` argument position. +* Added notifications for OpenCode's "Ask user question" tool. +* Show discount chip on models with active promotions in the model picker. +* Per-query image limit bumped to 20 (from 5) and per-conversation image limit bumped to 200 (from 20). +* Performance improvement preventing lagginess after logging in when you have many Warp Drive objects. +* Added support for file artifacts in agent conversations with download functionality and filtering options. + +**Bug fixes** + +* \[Windows] Fixed image paste into CLI coding agents (Claude Code, OpenCode, etc.). +* Fixed MCP server tags overflowing off-screen when a server has many chips (e.g. GitHub MCP with many repo scopes). +* Fixed MCP gallery items not being alphabetized consistently in the MCP servers settings page. +* Fixed artifacts card clipping the "Continue locally" button on narrow panes. +* Fixed code review submit button being incorrectly disabled when the terminal's working directory casing didn't match the on-disk repo path on macOS. +* Fixed new accounts not being marked as onboarded on the server when signing up after completing the onboarding slides from a non-login-slide entrypoint. +* Fixed Project Explorer getting stuck in loading state when opened after connecting to a remote SSH session. +* Fixed a bug where the agent's `read_files` tool returned extensionless text files (such as shell scripts) as binary content. +* Fixed MCP settings page file-based server badges growing unbounded and incorrectly labelling Warp-scoped servers as ".warp" instead of "global". +* Fixed missing in-progress indicator in agent panes when a shell command is running but no agent message has been sent yet. +* Fixed MCP OAuth authentication failing with providers that enforce strict redirect URI matching (e.g. Hydra/ORY). +* Fixed MCP tool calls with integer-typed parameters failing due to being serialized as floats. +* Fixed file edit tool dropping the end of a line when the LLM's search block ended with a partial line match. +* First find match now gets correctly selected when using the code editor with vim mode. +* Fixed code review comments being silently dropped when sent after cancelling a running agent command with Ctrl+C. +* Toolbar chips in the coding agent footer are no longer hard to read when running alt-screen CLI agents like OpenCode. +* Fixed MCP servers (e.g. Figma) requiring re-authentication on every app restart. +* \[Windows] Fixed a race condition that caused auto-updates to fail with file-in-use errors when Warp hadn't fully exited before the installer ran. +* Improved reliability of the Rich Input submission flow for Copilot CLI. +* \[Windows] Fixed unbounded memory growth when rendering large amounts of CJK text with a primary font that does not include CJK glyphs. +* Fixed settings search bar text overflowing when typing long queries. +* Fixed Oz CLI hanging after command completes when the network is unavailable. +* Fixed Ctrl+C not terminating the Oz CLI during shutdown. +* Fixed `~` (tilde) not being expanded to the home directory in the `/open-file` slash command. +* Fixed orchestration events breaking tool call ordering when a CLI subagent is active. + +**Oz updates** + +* Added a bundled Claude API skill for Claude API and Anthropic SDK development guidance. +* Added support for `--share public:{access_level}` to oz CLI to set public access level on oz cloud runs. +* `/feedback` skill now adds the `in-app-feedback` label to issues it files, for tracking. +* `start_agent` no longer rejects remote child agents when `environment_id` is omitted; within a remote parent, the child inherits the parent's environment automatically. + +### 2026.04.15 (v0.2026.04.15.08.45) + +**Improvements** + +* Agent Mode now shows a "Last seen by agent at" indicator for long-running commands, so you can see how recently the agent received new output. +* Added completions for npm package search, nx, brew, aws s3, tree, awk, sort, ip, uv, and nmap, and added pnpm workspace filter support. +* Skill invocations now display with the same purple highlighted text as slash commands in the input and prompt views. +* Added completions for `timedatectl`, `ack`, `watch`, `lsof`, `systemctl`, `ros2`, `nextflow`, `tsh`, `codex`, `asdf`, `sdk`, `pass`, `az`, `oc`, `scp`, `claude`, `git show`, `git rm`, `gsutil`, `aws ec2`, `docker-compose`, `yarn`, and `docker run`; improved `git switch`, `git diff`, `aws` static flags, `gt`, `kubectl`, `tf`, `pnpm`, `kubectl`, and SSH host completions; added `apt` repo package generator. +* Code review comment buttons now remain visible when AI is disabled; comments can be sent to CLI agent terminals (e.g. Claude Code). +* Review comments can now be sent to any available terminal in the tab, not just the focused one. If the focused terminal is busy, Warp will automatically route comments to another idle terminal in the same repo. +* Skills are now searchable from the @-context menu in Agent Mode, inserting `/{skill_name}` into the prompt. +* File-based MCP servers can now be configured via `~/.agents/.mcp.json` (global) or `.agents/.mcp.json` (project-local). + +**Bug fixes** + +* Fixed longer prompts for Claude Code not being fully submitted when using Rich Input in Warp. +* Fixed settings being reset to defaults when a logged-out user creates a new account. +* Updated openh264 dependency to resolve a heap overflow security vulnerability (GHSA-5pmw-9j92-3c4c). +* Show "Resume Conversation" shortcut when agent conversations fail with transport or server errors. +* Fixed `kubectl` resource completion breaking when `-n`/`--namespace` or other flags are placed before the subcommand. +* Fixed markdown files with animated GIFs and WebPs using excessive memory by rendering them as first-frame previews. +* Fixed autosuggestions and completions not appearing after shell bootstrap completes. +* Fixed excessive CPU usage from redundant `git status` processes when multiple terminal tabs are open in the same repository. +* Fixed a bug where conversations would stall if a long-running command finished while the user was in control. +* Fixed thought block headers ("Thought for X >") having a click area that extended to the full width of the pane; only the text and chevron are now clickable. +* Fixed global search using excessive memory when matching files with very long lines (e.g. minified JavaScript). +* Window title now respects custom tab names instead of always showing the generated name. +* Fixed `git push` branch completion for force-push and refspec prefixes, HTML entity rendering in completion specs, and `npm i` short-form command priority. +* Fixed repeated 403 errors when indexing large codebases. +* Fixed ask-question option rows changing cursor shape while hovering over option text. + +**Oz updates** + +* Local child agents now inherit the parent agent's AI profile (model and permissions). + +### 2026.04.08 (v0.2026.04.08.08.36) + +**New features** + +* Vertical tabs are now available, offering a new way to organize your terminal tabs in a sidebar layout. +* Tab configs allow you to save and share your workspace setup as customizable configurations. +* You can easily create new worktrees with autogenerated branch names. These are saved as tab configs to then customize and edit. +* New Rich Input available in third-party CLI agents (e.g. Claude Code, Codex, Gemini CLI, OpenCode, etc.). This allows you to use Warp's rich input features with these coding agents. +* Released a revamped notifications UI, and support for notifications for Claude Code and OpenCode. +* Added support for the coding agent toolbar for auggie and pie. +* Added a settings entry for the ask question tool to configure when it pauses for user input. + +**Improvements** + +* Conversation search now shows what it is searching for and its current activity. +* Added `warp://settings/appearance` deep link to open Appearance settings directly. +* Improved AI @context menu to prioritize blocks from the active terminal session and rank items by recency. +* Added support for rendering markdown tables in notebooks and Warp's built-in Markdown viewer. +* The command palette file opener now supports `~` (tilde) expansion to the home directory when searching for files. +* Added completions for `timedatectl`, `ack`, `watch`, `lsof`, `systemctl`, `ros2`, `nextflow`, `tsh`, `codex`, `asdf`, `sdk`, `pass`, `az`, `oc`, `scp`, `claude`, `git show`, `git rm`, `gsutil`, `aws ec2`, `docker-compose`, `yarn`, and `docker run`. +* Improved dynamic completions for `git switch`, `git diff`, `gt`, `kubectl`, `tf`, `pnpm`, `apt` and SSH hosts. + +**Bug fixes** + +* Added prompt changes to avoid agents getting stuck navigating pagers in Full Terminal Use. +* Removed the web inactivity logout that could sign out authenticated users unnecessarily while session-cookie expiration work lands. +* Skip ask-user-question prompts while auto-approve is enabled in Agent Mode. +* Fixed `git push` branch completion for force-push and refspec prefixes. +* Fixed HTML entity rendering in completion specs. +* Fixed `npm i` short-form command priority. + +**Oz updates** + +* Added an `oz whoami` command to get user information. + +### 2026.04.01 (v0.2026.04.01.08.39) + +**New features** + +* \[macOS] Right-clicking on text files in Finder allows you to open in Warp's code editor. +* Send code review comments, attach diff hunks as context, and send substrings as context (`cmd L`) to 3rd party CLI tools such as Claude Code, Codex, Opencode, etc. +* Oz agents can now ask users clarifying questions during Agent Mode interactions. +* Warp's agent now suggests followups when it is done. + +**Improvements** + +* Replaced warpify banner for subshell and SSH sessions with a footer to either warpify or tag an agent in. +* Improved error messaging when session sharing times out via CLI `--share` flag, now suggesting that it may be disabled by a team administrator. +* Added "Copy file path" option to the overflow menu in the file viewer for both code and markdown files. +* Added "Sign up" option to the settings gear menu for non-logged-in users. +* MCP config files edited by the agent now show an 'Open config' button in the code diff header, making it easy to jump directly to the config file. +* Added `/skills` support in CLI agent rich input for browsing and invoking agent-specific skills. +* Sandboxed Oz agents now have dedicated autonomy settings, instead of inheriting the team-level defaults. +* Updated settings info icon tooltips to clarify they open documentation. +* Improved quality and latency of prompt suggestions and suggested code diffs. +* Cloud agents can now accept images and file attachments as context. + +**Bug fixes** + +* Fixed stale fallback model messaging persisting across new user queries. +* Fixed scroll behavior when editing code review comments to properly reveal the comment editor. +* Fixed WebSocket proxy connections timing out when the proxy listens on port 80. +* Fixed PowerShell aliases and functions to be matched case-insensitively, matching PowerShell's native behavior. +* Fixed conversation search temp directory paths using mixed separators on Windows. +* Fixed keyboard shortcuts settings panel being empty when first navigated to via search. +* Fixed the `@` context menu dismissing after typing ~6 characters when filtering categories. +* Fixed a crash with Oz CLI commands that read from stdin. +* Fixed a production WebAssembly crash caused by native repository detection code being reached from shared Wasm call paths. +* Fixed links in blocklist code review comments not opening when clicked. +* Fixed "Out of credits" alert not dismissing when users provide their own API keys. +* Fixed link detection being offset in AI conversations after conversation summaries or hidden reasoning blocks. +* Simplified file explorer lazy-loaded folder handling and fixed transitions between standalone folders and indexed git repositories. +* Fixed inline code snippet colors and underline colors not updating when switching editor themes in notebooks. +* \[Windows] Fix rendering on an additional set of older Intel iGPU drivers. +* Fixed web auth flows so session-cookie-authenticated clients can call authenticated server APIs without requiring an Authorization header. + +**Oz updates** + +* Fixed Oz session sharing failing behind HTTP proxies on port 80. +* The `OZ_RUN_ID` environment variable is now available inside agent terminal sessions, set to the current task ID. +* Improved error messages when agent session sharing fails, removing repetitive text and providing clearer guidance. +* Oz agents can now ask users clarifying questions during Agent Mode interactions. + +### 2026.03.25 (v0.2026.03.25.08.24) + +**New features** + +* You can now use the pr-comments skill using `/pr-comments` to fetch Pull Request comments from GitHub. +* Warp now supports the Kitty Keyboard Protocol. + +**Improvements** + +* Onboarding now shows premium model tiers as disabled with an upgrade path for free users. +* All inline menus are now resizable, and some inline menus now have tabs. +* Adds new built-in `edit-figma-design` skill, invokable by users with Figma's remote MCP server installed. +* MCP server templates can now use dropdown selectors for enums. +* Added a customizable toolbelt for the agent input footer — drag and drop to rearrange context chips and controls. +* \[macOS] Migrate to Apple's newest icon format. This will allow Warp's icon to adapt to the chosen "Icon & Widget Style" preference if the default icon is selected. +* Code review comments can now be sent directly to running CLI agents (Claude Code, Gemini CLI, etc.) from the code review panel. +* Pressing `esc` now dismisses an empty code review comment composer. +* Added the ability to always show or always hide agent thinking blocks. Visit **Settings** > **AI** > **Other** to change. +* Add a `/changelog` command for reopening the latest changelog, and keep the update toast visible until dismissed. +* Added syntax highlighting for Dockerfiles in the file editor. +* Added a setting to hide agent-executed commands from shell history, now enabled by default. +* MCP servers detected from third-party agents (Claude, Codex) are now visible and spawnable from the MCP servers page in Warp's AI settings. For more, see our [docs](https://docs.warp.dev/agent-platform/warp-agents/mcp#file-based-mcp-servers) on file-based MCP servers. + +**Bug fixes** + +* Fixed visual jitter in agent toolbelt when opening the rich input composer. +* Clarified the `/fork` slash command description. +* MCP resource reads now respect autonomy settings instead of always prompting for approval. +* You now get completions, syntax highlighting, and hover descriptions when your flag/value pairs are `=`-separated, e.g. `--flag=value`. +* Fixed stale go-to-definition and symbol outlines when using code review with multiple tabs. +* Fixed an issue where selecting a shell command from command search (`cmd-r`) while in Agent Mode with auto-detection disabled would treat the command as an agent prompt instead of executing it as a shell command. +* Fixed `ctrl-c` not working during conversation search. +* Fixed an issue where the follow-up prompt in `/compact-and` and `/fork-and-compact` was silently lost when summarization failed or was cancelled. +* Fixed dismiss button and `ctrl-c` not working on suggested unit tests banner. +* Git diff chip now appears in remote and subshell sessions. +* Fixed input scrolling bug where clicks were sometimes applied one line up (instead of on the clicked line). +* Fixed rendering of programs that use the synchronized output VT extension in shared sessions, such as Claude Code. + +**Oz updates** +* Updated the `create-skill` bundled skill with the latest upstream version, adding eval/iteration workflow, benchmarking, and description optimization capabilities. +* New chip in AI input mode for GitHub pull requests, whenever you have a pull request open for your current branch. + +### 2026.03.18 (v0.2026.03.18.08.24) + +**New features** + +* Warp now automatically detects global and project-scoped MCP servers configured with `claude` or `codex`. Toggle **File-based MCP servers** in **Settings** > **AI** to auto-spawn servers based on your local configuration. See [docs](https://docs.warp.dev/agent-platform/warp-agents/mcp#file-based-mcp-servers) for more. +* Added Go to Line dialog in the code editor (`CTRL-G`) with line:column support. + +**Improvements** + +* Added "Leave Agent Thinking expanded" setting to keep agent thinking blocks expanded after streaming. +* Added "All" and "Current Directory" tabs to the inline conversations menu. +* Updated settings copy to consistently use "Oz" instead of "the Agent" in MCP Servers and Rules sections. +* Improved the performance of loading and rendering large AI conversations. +* Added an inline plan selector for conversations with multiple plans. +* \[macOS] The window traffic light buttons now look correct at different zoom levels. +* Kitty keyboard protocol support is now available on Preview builds. +* The Warp agent management view now links to associated skills for cloud agents. +* `Ctrl-R` command search now includes AI query history from all past conversations, not just those currently open. +* Enabled Kitty keyboard protocol support on dev builds. +* Improved the ranking of items listed in @ context by considering recency. +* Added new built-in skills `generate-figma-content` and `pull-figma-content` invokable by users with Figma's remote MCP server installed. +* Hidden directories and files (starting with `.`) now appear at the top of the Project Explorer, matching the convention used by most editors. +* Updated setup command placeholder to show `cd my-repo &&` example. + +**Bug fixes** + +* Fixed "for terminal" text in pane header becoming bold when disabled, causing a layout shift. +* Fixed notebook find bar showing `?/n` instead of proper match counter. +* Fixed bug where editing a tab title always started with the pane title (instead of the tab's custom title, if it existed). +* Fixed "View latest changelog" action not appearing in the command palette. +* Fixed issue where artifacts from cloud agent runs did not update live in the conversation details pane. +* Fixed intermittent "Failed to update plan" toast appearing without user action when background plan auto-saves encountered transient failures. +* Fixed tooltip for branch name in code review panel overlapping the truncated text — it now appears above the branch name. +* Fixed `Ctrl+G` not being bound by default for "Go to line" in the code editor. +* Fixed `cmd-O` files palette not toggling off when pressed again. +* Fixed code review panel unnecessarily resetting scroll position and cached state when switching tabs. +* Fixed some saved prompts not appearing in slash command menu when searching with a single character. +* Fixed SSH warpification not triggering when using shell aliases for SSH commands. +* Fixed a bug where SSH sessions run by the agent would incorrectly trigger warpification UI. +* Fixed issue on macOS where New Window/New Tab menu items and keybindings occasionally became disabled when using global hotkey window. +* Fixed code review branch dropdown only showing "Uncommitted changes" after closing and reopening the panel. +* Fixed "New environment" button in Environment settings not opening the setup mode selector popup. +* Fixed onboarding slides cutting off navigation buttons when the window is too short — content area is now scrollable. +* \[Windows] Fixed path inconsistencies that caused codebases to fail indexing. +* Show tooltip on the codebase indexing toggle when it is disabled by an admin policy, explaining why the setting cannot be changed. +* \[Windows] Fixed rendering issues on old Intel UHD integrated GPUs. +* Fixed a bug where only the first plan was shown inline when restoring a conversation with multiple plans created. +* Fixed resume-conversation keybinding not working when a long-running command subagent is active. +* Fixed broken documentation links in agent tips, settings, and onboarding content. +* Fixed AI queries in `Ctrl-R` history not being sorted by time. + +**Oz updates** + +* Conversation search now uses real file tools for faster, more accurate history search. +* Added `/open-repo` slash command for switching between indexed codebases. +* Added tabs to the up-arrow history menu to filter to commands or prompts. +* `oz agent run` now prints the run ID with a link to the Oz dashboard. + +### 2026.03.11 (v0.2026.03.04.08.20) + +**Bug fixes** + +* The terminal input now automatically detects references to Figma and encourages the use of the Figma MCP. Images exported from Figma are also detected. + +### 2026.03.05 (v0.2026.03.04.08.20) + +**New features** + +* Adds prompt customization for the new Warp prompt. + +**Improvements** + +* Adds new built-in skills `generate-figma-content` and `pull-figma-content` invokable by users with Figma's remote MCP server installed. +* Selected text is no longer auto-attached as agent context to prevent accidental attachment, and instead requires right click > attach as agent context. +* Cloud conversations now appear in the @conversations context menu. +* When Settings > MCP Servers > File-based MCP servers is toggled on, we now automatically detect and spawn global and project-scoped MCP servers installed via `codex`. +* Global search now pre-populates with the active text selection from code, terminal, notebook, and plan views. +* Warp prompt now has separate chips for git branch and git diff stats. +* Show pending prompt indicator when using `/fork-and-compact` or `/compact-and` with a follow-up prompt. +* Oz permission notifications now use "Oz" branding instead of "Agent Mode". +* \[macOS] The window traffic light buttons now look correct at different zoom levels. +* Added "Copy plan ID" option to the plan document overflow menu. + +**Bug fixes** + +* Fixed an issue where changing directories from the prompt chip dropdown cleared the terminal input. +* Fixed LSP error diagnostics (underlines) persisting on valid symbols after workspace reanalysis. +* Resolved an issue where duplicate skills installed across multiple provider directories (e.g., `.claude` and `.agents`) would appear twice. +* Fixed git diff stats chip incorrectly appearing in non-git directories. +* Fixed global hotkey window opening on the wrong screen after sleep/wake when pinned to a specific display. +* Fixed cursor position queries (`ESC[6n`) not working when connected via tmux control mode (`-CC`), which caused certain TUI applications to hang when Warpified in SSH (e.g. Codex CLI). +* Fixed agent driver not waiting for automatic error retry on network failures. +* Fixed incorrect ANSI colors in the Adeberry theme. +* Fixed a bug where some MCP servers would fail to connect due to an unsupported `resources/list` method. +* CLI now exits immediately with an error when credentials are invalid, instead of timing out while syncing Warp Drive. +* Fixed a crash that could occur when selecting text during rapid terminal output. +* Fixed ephemeral MCP servers not being included in multi-agent API requests. +* Fixed settings page not updating profile picture after auth state changes. +* Fixed the "Open in Warp" button not working for code snippets in restored and forked AI conversations. +* Hide the free cloud credits banner on shared sessions and WASM builds. +* Fixed a case where the newest plan created by the agent would not visually replace a previous plan that was open. +* "Plan synced to Warp Drive" toast no longer appears when the synced plan is in a different tab. +* Fixed "open file" button in code review diff view not working when the pane is maximized. +* Fixed git metadata background operations after a terminal is closed. +* Mobile soft keyboard will now work for LRCs. +* Oz agents now report more detailed information about session-sharing failures. + +**Oz updates** + +* Oz agent tasks now report structured error codes to the server, enabling better error tracking and retryability handling. +* Fixed Oz cloud agent not waiting for automatic error retry on network failures. +* Added support for passing arguments to skill invocations (`$ARGUMENTS`, `$N`) and for including user queries with the invocation. + +### 2026.02.25 (v0.2026.02.25.08.24) + +**New features** + +* Warp now has language server support in our native code editor. For details on the languages and features we support, check [https://docs.warp.dev/code/code-editor/language-server-protocol](https://docs.warp.dev/code/code-editor/language-server-protocol) + +**Improvements** + +* Reintroduced customization support for the Warp prompt. +* Maximizing the Code Review panel now opens the file list. +* Docker image inputs in environment settings now show a link to the Docker Hub page when available. +* Added `/compact-and` slash command to trigger conversation compaction and automatically send a follow-up prompt when it completes. +* Added a new `/profile` command that allows you to switch between profiles using an inline menu. +* Oz CLI now outputs a direct link to the Oz webapp run page when spawning cloud agents. + +**Bug fixes** + +* Fixed a bug where the Oz CLI would open the Warp GUI app rather than printing help output. +* Fixed broken documentation links on the Referrals settings page and AI settings page. +* Fix CLI agent footer detection when commands are prefixed with env var assignments. For example, `OPENCODE_EXPERIMENTAL_PLAN_MODE=1 opencode`. +* Fixed rendering of codebase search tool calls when restoring conversations +* Local-only slash commands such as `/open-file` are now disabled automatically in remote sessions +* Fixed "View all cloud runs" button linking to a specific run instead of the runs list page +* Fix tab alignment in monospace text blocks by using fixed-width tab stops. +* Improve cloud-mode modal routing for concurrent-limit vs out-of-credits states. +* Fix cloud-mode out-of-credits modal flicker and compact CTA alignment. +* \[Linux] The `oz` CLI package is now named `oz-stable`. + +**Oz updates** + +* Add "Default mode for new sessions" setting to open new tabs and panes in agent view by default. + +### 2026.02.18 (v0.2026.02.18.08.22) + +**New features** + +* Agents can now fetch and read content directly from URLs provided in your query. + +**Improvements** + +* Enabled multi-select in Notebooks and code editors. +* Added a new setting under `Appearance > Tabs` to preserve the active tab's color when creating new tabs. + +**Bug fixes** + +* Fixed Escape key closing the up-arrow menu instead of transitioning to normal mode when in vim insert mode. +* Fixed Option-left and Option-right keys not working for word navigation in code review comments editor. + +### 2026.02.11 (v0.2026.02.11.08.23) + +**Improvements** + +* Updated the tabs UI to be cleaner, more readable, and to make tab focus clearer. + +**Bug fixes** + +* Show the Input Type setting (Warp/PS1) regardless of global AI setting. + +### 2026.02.10 (v0.2026.02.10.11.37) + +**New features** + +#### Introducing Oz: orchestration for cloud agents + +![Introducting Oz image showing the new Oz logo and a preview of the oz.warp.dev site](https://releases.warp.dev/changelog_images/v0.2026.02.09.06.06.stable.png) + +Oz is Warp's orchestration platform for cloud agents: launch parallel agents, automate recurring engineering work, and build apps on top of agents with full visibility and control. + +[Read the launch post →](https://www.warp.dev/blog/oz-orchestration-platform-cloud-agents) + +#### Oz Cloud Agents + +* **Run Cloud Agents from anywhere with built-in tracking** — start agents from Warp or via the CLI, triggers, or schedules. Every run is auditable and steerable. [Cloud Agents docs →](https://docs.warp.dev/agent-platform/cloud-agents/overview) +* **Cloud environments for consistent execution** — configure Docker-based environments (unlimited repos + setup commands) and run agents in isolated cloud sandboxes. [Environments docs →](https://docs.warp.dev/agent-platform/cloud-agents/environments) +* **Track agents from the web** — manage runs, create schedules, configure environments, and set up integrations from any browser at [oz.warp.dev](https://oz.warp.dev). +* **Schedule agents based on Skills** — run agents automatically on a cron schedule for code cleanup, dependency updates, and issue triage. [Scheduled Agents docs →](https://docs.warp.dev/agent-platform/cloud-agents/triggers/scheduled-agents) +* **Programmable by default** — orchestrate agents via the CLI and integrate Oz into tools and services via the API/SDK. [API and CLI reference →](https://docs.warp.dev/reference) + +#### Warp Upgrades + +* **Agent Modality** — two distinct modes: a clean terminal for commands, and a dedicated conversation view for multi-turn agent workflows with full controls (model select, voice, attachments). +* **Cloud-Synced Conversations** — your agent conversations sync to the cloud and persist across devices. Share with teammates via link, view on the web, or continue locally. + +#### Agent Capabilities + +* **Skills** — reusable instruction sets that agents auto-discover from your project or home directory. Invoke with `/{skill-name}` or run as scheduled cloud agents for repeatable automation. [Skills docs →](https://docs.warp.dev/agent-platform/warp-agents/skills) +* **Computer Use** — agents can interact with desktop environments in sandboxed cloud containers—take screenshots, click, type, and test UI changes. [Computer Use docs →](https://docs.warp.dev/agent-platform/warp-agents/computer-use) + +### 2026.02.04 (v0.2026.02.04.08.20) + +**New features** + +* Added full support for the Kitty keyboard enhancement protocol, enabling TUI applications like OpenCode to detect and use enhanced keyboard input. +* Support agent footer when running Copilot CLI. +* Added a new paid plan, **Max**, which comes with 12× more monthly credits than Build. Upgrade in `Settings > Billing and Usage`. + +**Improvements** + +* Improved environment update handling with better timestamp tracking and immediate UI refresh after edits. +* `@` menu now shows function definitions when NLD is disabled. +* Conversation deep links now open in a new tab instead of a new window. +* Renamed `edit` slash command to `open`. +* Fixed a race condition when using API keys with the Oz CLI. +* Improved robustness of MCP connections (especially using the legacy SSE transport). "Transport closed" errors now trigger a reconnection to the server. +* Added a new setting to keep the opened/closed state of the tool panel consistent across tabs in the same window ("Tools panel visibility is consistent across tabs"). + +**Bug fixes** + +* Fixed "Sharing in Warp Drive" onboarding block appearing mid-stream during agent responses. +* Disabled codebase indexing on non-agent run commands. +* Fixed scrolling behavior when typing in long-running commands — cursor is now scrolled into view. +* Fixed sharing dialog copy link icon being slightly larger than the text. +* Fixed issue where the code review panel would get stuck on "Loading open changes" when multiple repositories are open in the same tab. +* Fixed a crash caused by orphaned wide character flags in the terminal grid. +* Fixed clipping issue in terminal message bar. + +### 2026.01.28 (v0.2026.01.28.08.14) + +**Improvements** + +* Files opened from code review panel, project explorer, and global search now respect your external editor setting. +* Toggling the plan while the pane is maximized now restores the layout to show the plan. +* Added "copy path" button to file headers in code review panel. +* Pasting images into the input now enters Agent Mode, matching drag and drop behavior. + +**Bug Fixes** + +* Fixed an issue where conversations could break when the agent read large images from directories. +* Fixed input buttons overflowing into adjacent panes in narrow layouts. +* Fixed text in MCP tool call details not being copyable. +* Fixed status indicator incorrectly showing for empty conversations in tab headers. +* Fixed Drive team section header displaying in all caps. +* Fixed Enter key not working in MCP installation modal. +* Fixed slash command text not highlighting correctly in some cases. +* Fixed input mode detection occasionally switching unexpectedly. +* Fixed /edit command failing when filename had trailing whitespace. + +### 2026.01.21 (v0.2026.01.21.08.14) + +**New Features** + +* Global search in files across your current directories. Use `CMD-F`/`CTRL-SHIFT-F` to open. +* Expanded web search support to additional models. + +**Improvements** + +* Save AI prompts as Agent Mode workflows via context menu. +* `/init` now generates AGENTS.md instead of WARP.md. +* Added horizontal autoscrolling when jumping to line/column. +* Better language detection for syntax highlighting. + +**Bug Fixes** + +* Fixed a memory leak that occurs when making an Agent Mode request. +* Fixed an issue where "waiting for a password" notifications could be triggered incorrectly when launching certain terminal apps like neovim. +* Fixed duplicate entries appearing in the agent management view for Slack-triggered conversations. +* Fixed alias expansion being triggered in AI input when it should only apply to shell commands. +* Fixed an issue where multiple shell commands could enter long-running mode in the same request batch. +* Hide AI options in the command palette when AI is disabled. +* Stopped highlighting search matches in reasoning blocks. +* Fixed session viewer input being cleared when agent runs commands. + +### 2026.01.14 (v0.2026.01.14.08.15) + +**New features** + +* Added footer for third party CLIs. +* Added onboarding flow for new users. + +**Improvements** + +* Fixed duplicate rule suggestions on dismiss and save. +* @-context search now matches on both name and content for notebooks, rules, and workflows. +* Updated checkbox checkmark to use foreground color for better theme consistency. +* Filter selections in the cloud agent management view now persist across app restarts. +* MCP servers with OAuth authentication can now be used in warp agent run if previously authenticated in the desktop app. + +**Bug fixes** + +* Fixed a bug where text in the MCP tool call detail wasn't selectable. +* Fixed agent thread banner text overflow on smaller screens. + +### 2026.01.07 (v0.2026.01.07.08.13) + +**New Features** + +* Added agent tips under the warping indicator. + +**Improvements** + +* Users can now create team-scoped API keys. +* Agent tip now leads with `WARP.md` when mentioning project-scoped rule files. +* The `oz agent run-cloud` command can now create cloud agent tasks that are shared with team members. +* Updated agent profile switching tip to better explain why users would want to switch profiles. +* Comments in the code review flow now render full width when there are 4 or fewer comments, improving readability. +* When the completions menu is opened (tab), no completion item is selected by default. Pressing enter while no completion is selected directly runs the command currently in the input. Upon selecting a completion, it now automatically shows up in the input. This more closely mirrors behavior in traditional terminals. +* The `oz agent run-cloud` command now supports saved prompts. +* We added a new full terminal use model selector in the agents profile page so that you can select a specific model for full terminal use work. + +**Bug fixes** + +* Improved out-of-memory handling for cloud agents. +* Fixed a configuration error creating team-scoped Warp-managed secrets. +* Fixed 'parameter not set' error in zsh when users have setopt nounset enabled. +* Fixed an issue where up arrow history could be ordered incorrectly on quit or restart Warp. + +### 2025.12.17 (v0.2025.12.17.17.17) + +**Improvements** + +* Warp now specifies what different models were used for in the credit transparency footer. +* You can choose whether forked conversations open in a split pane or new tab. +* `warp mcp list`, `warp environment list`, and `warp agent profile list` now support plain-text and JSON output. +* MCP server configurations are now displayed in integration details (i.e. `warp integration list`). +* Added support for configuring MCP servers in integrations. + +**Bug fixes** + +* Fixed a bug where Oz CLI runs could get stuck trying to run a denylisted command. + +### 2025.12.10 (v0.2025.12.10.08.12) + +**Improvements** + +* Added 'Initialize codebase' button to Code Review, which appears when you're in an uninitialized repo, making it easier to set up codebase indexing and LSP. +* Added a new sub-menu to the model picker for selecting the reasoning level of reasoning models. +* Added syntax highlighting for Vue template files. +* Added support for specifying custom models for agents, integrations, and scheduled agents using the `--model` flag. +* Added support for custom HTTP headers in MCP Streamable HTTP or SSE server connections. +* Added `/conversations` slash command with a clock-rewind icon to open the conversation history palette. +* Warp integrations will more proactively signal if the agent is blocked. + +**Bug fixes** + +* Fixed a bug where, in `Settings > Billing and usage`, the credit denomination wasn't set to the proper value for teams with auto-reload on. +* The code editor now opens to the right of the active tab when "Choose a layout to open files in Warp" is set to "New tab". +* Fixed mouse reporting for apps that don't use the alternate screen buffer, e.g. Radare2. + +### 2025.12.03 (v0.2025.12.03.08.12) + +**Improvements** + +* The Oz CLI now displays more detailed information when the agent tries to take a prohibited action. +* Allow dragging file paths from the Project Explorer into active terminal commands like claude code and gemini for referencing files and folders. + +**Bug fixes** + +* Fixed a bug that could cause unbounded memory growth when using Warpified subshells or the legacy (non-tmux) SSH Warpify implementation. +* Fixed a bug that could cause `comm` errors to appear in Warpified subshells. +* \[Windows] Fixed keybinding for "find in code editor." This is now `CTRL-SHIFT-F` and configurable from Settings > Keyboard shortcuts. +* Ensured that the Oz CLI is available automatically on macOS. +* Fixed toast messages showing "Notebook" instead of "Plan" when taking actions on Plans in Warp Drive. + +### 2025.11.19 (v0.2025.11.19.08.12) + +**New features** + +* MCP server configurations can now be shared with others on your team. You can install a server shared by your team with minimal configuration. +* Warp now provides out-of-box MCP servers for common services like Github and Linear that can be installed and run with a single click. +* Find now works in the code review pane. + +### 2025.11.18 (v0.2025.11.18.12.24) + +**New features** + +* [Full Terminal Use](https://docs.warp.dev/agent-platform/warp-agents/full-terminal-use): Let the agent use the terminal as you would: interact with REPLs, debuggers, and full-screen apps like `top`. Warp is the only product on the market with Full Terminal Use capabilities. +* [`/plan`](https://docs.warp.dev/agent-platform/warp-agents/planning): do spec-driven development in Warp. Work with an agent to align on an implementation plan that can be saved, versioned, and even attached to a PR for teammates. +* [Interactive Code Review](https://docs.warp.dev/agent-platform/warp-agents/interactive-code-review): Review an agent's code like you would a teammate's, directly in Warp, and ask the agent to address the comments. +* [Slack and Linear integrations](https://docs.warp.dev/agent-platform/cloud-agents/integrations):\*\* Ask the agent to get to work from the tools you already use, track their progress, and take the wheel via live session sharing. +* Warp's Agents can now [search the web](https://docs.warp.dev/agent-platform/warp-agents/web-search) to retrieve information, when relevant. This capability is configurable via Agent Profiles. + +### 2025.11.12 (v0.2025.11.12.08.12) + +**Improvements** + +* \[Vim mode] Paragraph text objects are now supported, e.g. `dip` to delete a paragraph. +* \[Vim mode] In terminal mode, press `K` over part of a command to inspect it. +* Agent notifications now reference conversations' titles instead of their queries. + +**Bug Fixes** + +* The copy link button now works as expected after shared sessions have been closed. + +### 2025.11.05 (v0.2025.11.05.08.12) + +**New Features** + +* From the code review panel, add file diffs or the entire diff set as context to an agent conversation. + +**Improvements** + +* Warp now defaults to requiring approval before the agent will execute a command. +* Shared session links will open in a new tab by default, rather than a new window. +* Display summarization tokens when conversation summarization is triggered. + +### 2025.10.29 (v0.2025.10.29.08.12) + +**Improvements** + +* Display conversation summaries when summarization is triggered. +* Added completions for the Oz CLI. +* Updated community links from Discord to Slack throughout the app. + +**Bug Fixes** + +* Reduce padding on restored Agent Mode blocks and expanded shell commands. +* Add support for delete key in vim mode in code editors. +* Fix rendering for multi-line Agent Mode shell commands. + +### 2025.10.22 (v0.2025.10.22.08.13) + +**New Features** + +* Warp will suggest new unit tests in addition to code fixes via Suggested Code Banners + +**Improvements** + +* Fixed an issue where the model specs menu would get cut off. + +**Bug Fixes** + +* Fixed the close icon from becoming too small on the Warp Drive notebook viewer. +* Fixed an issue where the CLI would report invalid debug IDs in its troubleshooting output. + +### 2025.10.15 (v0.2025.10.15.08.12) + +**New Features** + +* Warp now supports scaling the entire application. Change the zoom level in `Settings > Appearance > Window` or by pressing `CMD-+` on macOS or `CTRL-+` on Windows / Linux. + +**Improvements** + +* The code review pane can now show diffs against other base branches. +* Added confirmation dialog when cancelling AI summarization requests. +* You can now expand Suggested Code Diffs further on down arrow. +* Restore closed panes using `CMD-SHIFT-T` or `CTRL-ALT-T` on Windows / Linux within 60 seconds of them being closed. +* Added shell completions for the Oz CLI. +* Warp Drive Environment Variables are now supported for Warp for Windows (PowerShell, Git Bash, and WSL). +* Enriched the model picker to include detailed specs of each model's intelligence, speed and cost. + +**Bug Fixes** + +* Fixed the custom window size setting not reliably applying on startup. + +### 2025.10.08 (v0.2025.10.08.08.12) + +**Improvements** + +* Added the ability to sort team members by usage in `Settings > Billing and usage`. +* Added UI indication of when Agent Mode conversation summarization is in progress, with a cancellation confirmation dialog. +* Made the sizing for headings consistent across all collapsible blocks. +* `@` menu no longer appears when running JS package manager subcommands, like `yarn workspace @org/package add`. +* \[macOS] Resolved an issue re-mapping keybindings that conflict with macOS keybindings. + +**Bug Fixes** + +* Agent Mode requested command previews now only show the first line of multi-line commands. +* Removed misleading "auto-approve" button while Warp is generating a fix for failed terminal commands. + +### 2025.10.01 (v0.2025.10.01.08.12) + +**Improvements** + +* Editing suggested file changes now takes place in the same pane, instead of a new tab. +* When using the `@` context menu outside of a repo, current folder's contents are now listed. +* The code mode file picker will now display gitignored files. +* \[macOS] Warp now stores session restoration data in a more-secure application container. + +### 2025.09.24 (v0.2025.09.24.08.11) + +**New features** + +* You can now create new files directly in Warp. Search "New File" in the command palette. macOS users can find it in the app menu under "File". + +**Improvements** + +* Change the "Reject" label to "Refine" for code diffs and plans. They're functionally the same, though we think this will clear up some confusion over what hitting "Reject" will do. +* Added realtime form validation to Environment Variables when secret redaction is enabled. +* Avoid showing the `@` context completions menu when typing a package name. This covers common installers for JS, Python, Ruby, Go, PHP, and more. +* Add an "auto-approve" option with a keyboard shortcut for requested commands and MCP tool calls. This makes it easier to accept a command and auto-approve future commands in a single button. + +**Bug fixes** + +* Fixed error with fish shell v4. +* Avoid showing multiple "stopped task" banners when toggling a resumed conversation back to stopped before the agent begins responding. +* Fix input problems with Russian on PowerShell. + +### 2025.09.17 (v0.2025.09.17.08.11) + +**New Features** + +* Warp agents are now available via the command line! [Learn more](https://docs.warp.dev/reference/cli) +* Added support for custom Regex names in Enterprise Secret Redaction. + +**Improvements** + +* The @ context menu can now be activated outside of Git repositories (for actions such as attaching blocks/workflows), when in autodetection or AI input mode. +* move the auto-approve button alongside the agent "stop" button for easier access. +* Move the "stop" button alongside the "Warping..." indicator. This restores the "stop" button to classic input users, and offers a more intuitive experience for universal input users. +* Added right-click context menu to code review pane with split pane controls. +* Files selected in the file tree now open in a preview mode until interacted with. +* Warp's agent now shows reasoning traces from reasoning models. +* Ctrl-c during a long running command run by the agent will also stop the agent, not just the command. + +**Bug Fixes** + +* Fixed nested lists in agent markdown output sometimes not rendering properly. +* Fix slow scrolling on macOS Tahoe. +* Fix todo lists overflowing off of the screen for 10 or more items. +* Fix code review maximize button appearing outside of split pane mode. +* Fix the stop button unexpectedly disappearing when accepting the "start a new conversation" suggestion. + +### 2025.09.10 (v0.2025.09.10.08.11) + +**Improvements** + +* Added support for ignoring input suggestions. Click the X next to an item in your up-arrow history menu to hide that from showing up again. You can also enable the `Show autosuggestion ignore button` setting to add an X to autosuggestions directly in your input. +* Git UI detects more changes in git worktrees. +* You can now rename/delete items in the file picker and open them with the system file explorer. +* Combine "refine" and "cancel" buttons into a single "reject" button. This lets you give feedback on code diffs, commands, and plans with a single button. +* You can now switch node versions by clicking on the node version chip. +* Added a "New Agent" button to the agent management panel to start a new agent conversation more easily." + +**Bug fixes** + +* Fixed an issue where agent output in a code block could be inserted at the wrong place. +* Fixed code review diff buttons incorrectly receiving mouse events. +* Avoid auto-expanding an agent's requested commands while you are using voice dictation. +* Add back the auto-approve button for classic input mode. +* Fixed keyboard navigation of chip menus in the input while an agent is running. +* Properly reset context when user sends query to agent. + +### 2025.09.03 (v0.2025.09.03.08.11) + +**Improvements** + +* Added support for rendering H4-H6 in markdown. + +### 2025.09.01 (v0.2025.09.01.20.54) + +**New features** + +* Revert diff hunks directly from the Code Review Pane. +* Add lines of a file to the context of a conversation from the Warp code editor. +* You can now search and restore Agent conversations in your history using the `conversations:` prefix. +* You can now search and navigate to indexed codebases using the `repos:` prefix. + +**Improvements** + +* Voice transcriptions are no longer cut off when unfocusing an input editor. +* You can now select the $EDITOR environment variable as the default application for opening file links. +* Added new header treatment for unfocused Warp windows. +* \[macOS] A new dock icon option to celebrate Code Country - the Cow icon! (`Appearance > Icon` to change) +* Pasting images in the terminal input switches to Agent Mode and attaches the image as context. +* Added support for the Streamable HTTP transport for MCP servers. + +**Bug fixes** + +* \[Windows/Linux] Fixed keybinding conflict for split pane down action for the Input, when a code diff is not active. +* Fixed tab tooltips displaying unwanted leading and trailing whitespace. +* Pressing the up key while the model picker is open no longer opens the command history. Opening the model picker while the command history is open now closes the command history. + +### 2025.08.27 (v0.2025.08.27.08.11) + +**New Features** + +* [Agent Profiles](https://docs.warp.dev/agent-platform/warp-agents/agent-profiles-permissions#agent-profiles): define how your agent operates. +* New pane to view changes to a Git repository. +* Files now open in a tabbed viewer. +* Syntax highlighting for Scala files in Warp. + +**Bug Fixes** + +* Fix paths not inserted when pasted images are not attached. + +### 2025.08.20 (v0.2025.08.20.08.11) + +**New features** + +* [Suggested Code Diffs](https://docs.warp.dev/agent-platform/warp-agents/active-ai#suggested-code-diffs) - Warp now intelligently suggests the appropriate fixes for any simple errors encountered in the command line e.g. compiler errors. Head to `Settings > Active AI` to toggle this feature. + +**Improvements** + +* Added setting to hide fixed prompt suggestions. +* Updated default input type from 'Classic' to 'Universal'. +* Improve the styling and usability of tabs for narrow windows. + +**Bug fixes** + +* Fix failures to start zsh sessions when using prezto. +* The agent status indicator no longer disappears while a command is running. +* Selecting a workflow will correctly close the workflows menu. +* Don't auto-attach image if file pasted as plaintext. +* Fixed issue with drag-drop images. +* Fixed display of completions that may have included special characters. + +### 2025.08.13 (v0.2025.08.13.08.12) + +**New Features** + +* Agent Mode now displays interactive code blocks when referencing snippets from your codebase. You can easily copy the snippet, add the snippet as Agent Mode context, or open the file in Warp's built-in editor. +* Agent Mode now creates and tracks task lists for more complex workflows. See [Agent Task Lists](https://docs.warp.dev/agent-platform/warp-agents/task-lists). +* Added support for defining project-scoped rules with a WARP.md file. See [Rules](https://docs.warp.dev/knowledge-and-collaboration/rules#project-scoped-rules). +* Added Slash Commands (/) in Agent Mode or Auto-Detection Mode to quickly run built-in actions or saved prompts without leaving the input field. See [Slash Commands](https://docs.warp.dev/agent-platform/warp-agents/slash-commands). + +**Improvements** + +* Added syntax highlighting for SQL in Warp's code editor. +* Added button to dismiss suggestions footer. +* \[Linux and Windows] Added support for drag-dropping multiple images. +* New files in Warp open in a pane by default. You can customize this behavior via `Settings > Features > General > Choose a layout to open files in Warp`, where you can switch between opening files in a pane or a new tab. +* Input stays in Agent Mode after an image is attached, instead of switching to shell mode. + +**Bug Fixes** + +* Fixed behavior when clicking Agents chip in Classic input mode. +* Repository-scoped Warp features are now available in git worktrees. +* Fixed drag-drop of images for long-running commands (eg Claude Code, vim). +* \[Linux and Windows] Fixed attaching images from pasted files. +* Fixed "Find in selected block" feature after clicking on an active running block. +* Fixed text overlap on narrow panes with Classic Warp Prompt with Same Line Prompt. +* \[macOS] Fixed a bug that would cause text to disappear for very long Agent Mode prompts. + +### 2025.08.06 (v0.2025.08.06.08.12) + +**New Features** + +* GPT-5 is now available to all users. Use the model selector in the input bar to try it yourself. +* \[macOS] Added the ability to attach images as context by drag-and-dropping them or pasting from your clipboard. + +**Improvements** + +* You can now open any files within Warp's editor (including txt/csv files)! +* Warp can now edit Bazel files. +* Warp can now edit `.bashrc` and `.zshrc` files. +* Added `Always show secrets` to Secret Redaction for a less obtrusive secret redaction mode. +* Added reset time to the Billing and usage menu. + +**Bug Fixes** + +* Fix fish version <= 3.7 when vi keybindings were activated. +* Fixed bug affecting the "Open in Markdown Viewer by default" setting, you can use this setting to determine whether you'd like to view/edit MD files in Warp by default. +* Fixed an issue where typeahead for the next command could be lost if you typed really quickly after hitting enter on the previous command. +* Resolved an issue where stopping voice recording via the button would interrupt transcription. + +### 2025.07.30 (v0.2025.07.30.08.12) + +**New Features** + +* You can now set a configurable block size limit for higher scrollback limits! Head to `Settings > Features > Session > Maximum rows in a block` to configure. +* \[Linux] Added support for pasting images as context. + +**Improvements** + +* The "Open in Warp" banner now supports code files. +* When using Agent Mode, user-configured redaction rules are now applied to the contents of diffs and files, in addition to terminal blocks. +* Add SHIFT-ENTER keybinding. Claude Code users can use this to add linefeeds to their prompt. +* Added an overflow menu button in the top right of AI blocks for copying contents. + +**Bug Fixes** + +* Deleted files no longer appear in the @-context selection box. +* Users with Turkish locale will no longer see an extra letter "i" between commands. +* \[Windows] Restored windows will no longer be positioned with the title bar above the top of the display. + +### 2025.07.23 (v0.2025.07.23.08.12) + +**New Features** + +* \[Windows] Added support for pasting images from Clipboard into Agent Mode context. + +**Improvements** + +* Added image filename when pasting images into Agent Mode context. +* Added support for restarting MCP servers when Warp restarts. +* Added support for copying AI block and conversation contents via the context menu. +* Added Node.js prompt chip. + +**Bug Fixes** + +* Fixed a bug where attaching a block as AI context would reset the input state. +* Fixed a spacing issue with horizontal scrollbars in agent planning view. +* Added support for auto-expanding manually executed Agent Mode suggested commands. +* Fixed a bug where Warp would hang while updating code symbols in the @-context menu. +* Modified secret redaction regexes to be case sensitive. Use a `(?i)` prefix to make your regex case insensitive. +* Modified the Universal Input to no longer exit a conversation via "backspace". + +### 2025.07.16 (v0.2025.07.16.08.12) + +**New Features** + +* \[macOS] Support pasting images from clipboard into Agent Mode context. +* Migrated Warp's built-in set of Secret Redaction regexes into user's regexes, giving users more fine-grained control over their secret redaction. +* Added support for Find and Replace using `CMD-F` when viewing diffs or editing files in the built-in code editor. + +**Improvements** + +* Removed lock icon from Secret Redaction in favor of asterisks when ligatures are enabled. +* Added individual keybinding shortcuts to change input modes. + +**Bug Fixes** + +* Fixed an issue where the hover tooltip for disabled prompt suggestions either didn't render at all or was incredibly hard to read. +* Fixed the background color of inline code in restored AI blocks. + +### 2025.07.09 (v0.2025.07.09.08.11) + +**New Features** + +* New secret redaction strikethrough UI. Comes with new `Settings > Privacy > Hide secrets in block list` setting that defaults to off. + +**Improvements** + +* You can now resume stopped AI conversations: `CTRL-C` to stop and `CMD-SHIFT-R` to resume on macOS or `CTRL-SHIFT-R` on Windows and Linux. +* Code Diff view's default Edit and Revise keybindings changed and made configurable. +* Added syntax highlighting for PowerShell, Kotlin and Swift. + +**Bug Fixes** + +* Fixed an issue with `.inc` file chunking. +* Clicking on an active, long running block will no longer select the block, but focus the input. + +### 2025.07.02 (v0.2025.07.02.08.36) + +**New features** + +* Tab close button can now be set to the left. + +**Improvements** + +* Added syntax highlighting for TOML, PHP, Lua, Ruby, and Groovy (with Java syntax). +* Added conda chip support to new Universal Input prompt. +* Increased color contrast on tabs. +* Added "Upgrade" menu item for free users and "Billing and Usage" menu item for paid users in the user menu for easier access to subscription management. + +**Bug fixes** + +* When AI is disabled, ESC should no longer enter Agent Mode. +* Fixed an issue on WSL where files created by Agent Mode would have CRLF line endings. +* \[macOS] Tweaked autoupdate logic to more reliably remove old applications off disk. +* Fixed "Manage plan suggestion setting" link. + +### 2025.06.25 (v0.2025.06.25.08.12) + +**New Features** + +* Git branch and directory chip now are searchable. + +**Improvements** + +* Added support for HCL syntax highlighting in Terraform files. + +**Bug Fixes** + +* Fixed potential crash when displaying context chips with Unicode characters in file paths. +* Fixed a rendering issue with line numbers in suggested diffs. +* Attach context chip no longer appears if there is no context you can attach. + +### 2025.06.20 (v0.2025.06.20.22.47) + +**New Features**\ +\ +**Warp 2.0 is here - The Agentic Development Environment** + +Built from the ground up for agentic workflows, Warp is the most powerful tool for prompting, coding, and collaborating with multiple agents. + +**Multithread yourself with agents** + +* Launch intelligent tasks (agents) with a prompt. Agents gather context using CLI commands, MCP, Warp Drive, and Codebase Context. +* New Agent Management Panel to monitor, multitask, and intervene across multiple agents. +* Set autonomy controls and get notified when agents need your help. + +**A state-of-the-art coding platform** + +* 70% on SWE-bench, #1 on Terminal-Bench — the highest quality coding agent available. +* Codebase Context: Warp indexes and understands your codebase, allowing you to debug and write code faster without storing any code on Warp's servers. +* Review and edit diffs directly in Warp's native code editor. + +**Still a great command-line**\n- + +* A new Universal Input: run commands or prompt agents from a single interface. Lock into command mode or Agent Mode, or let Warp detect automatically. +* Choose your model, continue a conversation, attach images, link URLs, or reference files using `@`. +* Modern, IDE-like terminal experience with completions, predictions, and mouse support, all built natively in Rust for performance. + +**Context for your teammates and agents** + +* A knowledge store where you can configure MCP, define Rules, and store shared commands, notebooks, env vars, and prompts as context. + +All of this comes with higher AI usage limits on our Pro and Turbo plans, plus new pay-as-you-go overages for continued access to premium models.\ +\ +**Watch the full Warp 2.0 launch event →** [**warp.dev/future**](https://warp.dev/future) + +### 2025.06.11 (v0.2025.06.11.08.11) + +**New Features** + +* You can now attach images as context for Agent Mode! Simply use the image icon and select the files you wish to attach. + +**Improvements** + +* \[Linux] Added support for standard installed Zed and Zed Preview as default code editors. +* \[macOS] Added support for Zed Preview as a default code editor. +* Added syntax highlighting support for TSX and JSX. +* Increased visibility of non-focused diff hunks when navigating diffs. +* New Agent Mode output will no longer force-scroll. + +**Bug Fixes** + +* Fixed keybinding being missing for editing requested commands. +* Removed keybindings for zero-state prompt suggestions, to avoid conflicting with tab switching keybindings. + +### 2025.06.04 (v0.2025.06.04.08.11) + +**New Features** + +* Sonnet 4 is now an available model (enabled by default in the "auto" model). + +**Improvements** + +* Press the hovering fast-forward button to auto-execute all Agent actions until the task completes. +* Added ability to share session via `RIGHT-CLICK` on tab. +* You can now give the Agent permission to auto-execute MCP tool calls. + +**Bug Fixes** + +* Fixed an issue where Agent Mode would sometimes not find untracked files in Git repos. +* Fixed Agent Mode file editor randomly scrolling to the first line of a file. + +### 2025.05.28 (v0.2025.05.28.08.11) + +**New Features** + +* Added MCP server support. It's now possible to extend Agent Mode's capabilities using programs that support the [Model Context Protocol](https://docs.warp.dev/knowledge-and-collaboration/mcp). + +### 2025.05.21 (v0.2025.05.21.08.11) + +**New Features** + +* Set new Agent Mode permissions around executing commands, reading files, coding, and planning in AI settings. + +**Improvements** + +* You can now choose the coding model behind Agent Mode. +* Agent Mode conversations can now be paused via a hovering control panel in the right corner. +* Improved maximum block output capacity to 50k lines. + +**Bug Fixes** + +* Fix edit icon positioning for shared sessions. + +### 2025.05.14 (v0.2025.05.14.08.11) + +**Improvements** + +* Introduced refining functionality for requested commands. +* Added ability to continue previous Agent Mode conversations directly from response blocks. +* Overhauled the editing experience for suggested plans. +* Renamed input auto-detection setting to natural language detection in Command Palette for better clarity. +* Zero-state prompt suggestion chips are now horizontally clipped instead of being individually shrunk. + +**Bug Fixes** + +* Fixed incorrect ordering in history of executed commands and Agent Mode queries. +* Copying text from Agent Mode plans and suggested code changes now works more reliably. +* \[Windows] Made some changes to reduce false-positives from virus scanners. + +### 2025.05.07 (v0.2025.05.07.08.12) + +**Improvements** + +* Redesigned env var collection block UX. +* Added ability to embed Warp Drive Prompts inside Notebooks. +* Added AI block loading animation. +* Added ability to select and continue previous Agent Mode conversations. +* \[macOS] Improved time to update and relaunch Warp. + +**Bug Fixes** + +* Fixed a bug where escape was clearing autosuggestions in Vim's insert mode. +* Stopped showing an unexpected block in the planning output for o3. +* \[Windows] Fixed a bug when hovering symlinks in WSL sessions. +* Fixed terminal input remaining hidden after cancelling an env var block. +* Prevented unexpected empty code fences in Agent Mode when using Gemini 2.5 Pro or o3. + +### 2025.04.30 (v0.2025.04.30.08.11) + +**New Features** + +* Added desktop notifications for Agent Mode. Now, you can be notified when an agent completes a task, or when an agent needs your attention to continue (i.e. to review a command, to run an unsafe command, etc). You can configure these settings from `Features > Notifications`. + +**Improvements** + +* Agent Mode is now more robust at applying code diffs. +* Redesigned requested commands UX. +* Improved readability for "needs password prompt" desktop notifications. + +### 2025.04.23 (v0.2025.04.23.08.11) + +**Improvements** + +* Restored Agent Mode conversations can now be continued. +* Agent Mode now has access to a filepath search tool for coding tasks. +* Improved the reliability and positioning of suggestion dialogs for rules and Agent Mode workflows. +* We reworked the command palette search to make it more useful. + +**Bug Fixes** + +* Fix XML parse errors complaining that a "thought" cannot be empty. +* \[Windows] Fixed an issue where Agent Mode would fail to search when in WSL or Git Bash. +* Show "copy" button and other text selection tools when right clicking selected environment variable text. +* Fixed old shortcuts icon appearing in new tab page, if recommended AI prompts are disabled. +* Fish commands containing syntax errors now correctly "finish" the block. + +### 2025.04.16 (v0.2025.04.16.08.11) + +**New features** + +* After editing a code diff, you will now be returned to your original Agent Mode conversation. +* Commands with certain invalid arguments will no longer be suggested, such as file paths, git branches, and docker images. +* \[Windows/Linux] You can now open launch configurations in the current window with `SHIFT-ENTER` or `CTRL-ENTER` on the Command Palette. +* Added more default regexes for Secret Redaction, pertaining to AI API keys. +* Typing `ESC` in the terminal input editor now clears any Autosuggestions. + +**Bug Fixes** + +* Fixed issue with rendering performance for file links in AI output. +* Fixed an issue that causes Warp to crash when Agent Mode outputs broken links. +* New tab page no longer falls back to email if display name is not set. +* Fixed prompt chips not being clickable in new session with prompt pinned to top. +* Agent Mode now properly greps for queries containing double quotes. + +### 2025.04.09 (v0.2025.04.09.08.11) + +**New features** + +* Recommended AI prompts are shown in new tabs, go to Settings > Features to disable. + +**Improvements** + +* Agent Mode is now better at searching for exact function / symbol / etc. names in your code. +* Fix text selection for environment variable blocks. +* You can now attach select text in a code block as the Agent Mode context. +* Warp now supports marked text in the IME (non-English keyboards). +* Make text selectable for non-expandable command outputs (ex. failed agent tasks). +* Zero-state chips are no longer shown when entering AI input with a non-empty input buffer. + +**Bug fixes** + +* Fixed a bug that prevented copying of selected text of a code block when Agent Mode is enabled. +* Fixed a bug that allows a selection in the code block and a selection on the text simultaneously. +* \[macOS] Fixed shells installed via Homebrew not appearing in the list of available shells. + +### 2025.04.02 (v0.2025.04.02.08.11) + +**New features** + +* Get early access to unreleased and experimental features with [Warp Preview](https://docs.warp.dev/support-and-community/community/warp-preview-and-alpha-program). + +**Improvements** + +* Improved login item management to respect when users manually remove Warp from login items in System Preferences. +* The input editor now supports `CMD-SHIFT-UP/DOWN` on macOS or `CTRL-SHIFT-HOME/END` on Windows/ to move and select to the top/bottom of the text buffer. +* Removed 3-hour conversation timeout, allowing AI conversations to remain active indefinitely. +* Show a small popup when users who are at AI limits have their quota reset. +* Display a notification when AI request quota resets after hitting the limit in the previous billing cycle. +* \[Windows] Added “Open Warp in new tab / window” item for folders in the File Explorer context menu under “Show more options”. + +**Bug fixes** + +* Minor fixes for iTerm and Kitty images. +* Fixed regression related to using keyboard shortcuts to navigate a command in an empty split pane. +* Fixed some issues with Agent Mode failing to read files. +* Click targets in scroll views should more reliably click while moving the mouse. +* \[Linux] Window corners are correctly rounded with themes having background images. +* Fix a few common failure modes for Agent Mode response deserialization errors. + +### 2025.03.26 (v0.2025.03.26.08.10) + +**New features** + +* Kitty Image Protocol is now supported on macOS and Linux! + +**Improvements** + +* Agents may suggest using Dispatch to create a plan for complex tasks. You can disable suggestions to create plans under `Settings > AI > Dispatch`. +* You can now resume auto-execution of a previously dispatched plan if your follow-up query is set to "Dispatch", instead of creating a new plan. +* Added a keyboard shortcut to accept the most recent command correction. +* Zero-state suggestions are no longer shown when using a saved Prompt or past AI query. +* Tabs will not resize while hovered, making closing multiple tabs easier. +* The warning dialog for closing sessions now responds to the `ENTER` and `ESC` keys. +* Selected text within Agent responses can now be copied via the `RIGHT-CLICK` menu. +* \[Windows/Linux] You can now toggle whether a block is selected using `CTRL+CLICK`. + +**Bug fixes** + +* Fixed an issue that caused Agent Mode blocks to be incorrectly highlighted when performing rectangular selection. +* Fixed an issue where duplicate cloud preferences could be created during sync operations. +* Fixed keyboard shortcut padding for prompt suggestions. +* Fixed color contrast issues with light themes for the Pair & Dispatch chip in Prompt Editor. +* Agent Mode will no longer default to Windows-style line endings when creating a new file on macOS or Linux. +* PowerShell sessions will start even if the profile has a terminating error. +* The numpad `ENTER` key now behaves like the `ENTER` key in Agent Mode. +* \[macOS] Fixed a scenario where Warp would beachball while updating. +* \[Windows] In WSL, show completions for symlinked files. +* \[Windows] Fixed completions with `.exe` suffixes. +* \[Windows] Fixed setting Git Bash custom shell paths. + +### 2025.03.12 (v0.2025.03.12.08.02) + +**New features** + +* Agent Mode output is now rendered with Markdown formatting. +* You can now change the font used for Agent Mode output (Settings > Appearance). + +**Improvements** + +* \[Windows] Significantly improved pseudoconsole throughput (\~3x improvement). +* The Agent Mode model will now automatically select the best model based on your specific task. +* Ordered lists in Markdown now uses alphabetical or Roman numeral labels when nested. +* \[Windows] We now search more locations for a PowerShell executable. +* Reduced the size of Markdown headings. + +**Bug fixes** + +* Control whether Warp starts at login via a setting under Settings > Features > Start Warp at login (macOS only). +* \[Windows] Fixed an issue where dynamic enums commands weren't being executed. +* Fixed a bug with the mouse cursor when hovering over buttons. +* Fixed a bug that causes high CPU load with codebase context. + +### 2025.03.05 (v0.2025.03.05.08.02) + +**New features** + +* iTerm Image Protocol is now supported on macOS and Linux! +* \[macOS] Warp now starts at login (can be disabled in System Settings > Login Items & Extensions). + +**Improvements** + +* Input mode automatically returns to command mode when a command is detected in an AI follow-up request. (Only applies if natural language detection is turned on.) +* Text selections can now be attached to Agent Mode queries as context. +* \[Windows] Window transparency now works when using DirectX 12. +* \[Windows] Added “Open Warp Here” item for folders in the File Explorer context menu under “Show more options”. + +**Bug fixes** + +* Fixed an issue where `bazel` completions could use up a lot of CPU. +* \[macOS] Fixed a regression where the title bar would be transparent in fullscreen windows. +* \[Windows] Fixed children of shell processes not always exiting properly at shell termination. +* \[Windows] Fixed Warpification for custom-built WSL distributions. +* \[Windows] Fixed Ctrl-Up and Ctrl-Down shortcuts not working in alt screen programs (e.g. vim and emacs). +* \[Windows] Fixed last line of output getting truncated with some prompt configs in WSL. +* \[Windows] Fixed some hangs when using Agent Mode. +* \[Windows] Fixed issues starting PowerShell in strict mode. +* \[Windows] Fixed an issue where `.` would turn into n in ZSH when using ohmyzsh in WSL with an Italian keyboard layout. + +### 2025.02.26 (v0.2025.02.26.08.02) + +**New features** + +* Warp is now available for Windows! See our [Quickstart Guide](https://docs.warp.dev/getting-started/installation-and-setup#windows) +* Prompt, plan, and execute fully autonomous tasks from [Agent Mode with Dispatch](https://docs.warp.dev/agent-platform/warp-agents/interacting-with-agents) (Beta) +* Add codebase context support to Agent Mode. Currently enabled for Git repositories only. +* \[macOS] You can now customize your [App Icon](https://docs.warp.dev/terminal/appearance/app-icons) in `Settings > Appearance > Icon`. +* Create and store [Rules](https://docs.warp.dev/knowledge-and-collaboration/rules) to use as Agent Mode context. +* Show default suggestions in Agent Mode input. + +**Bug fixes** + +* Multicursor input is now `ALT` on Linux and Windows. +* Fix prompt chip misalignment for certain fonts. +* Autosuggestions remain visible when the input is not focused, to prevent height flickering when the autosuggestion soft wraps. + +### 2025.02.19 (v0.2025.02.19.08.02) + +**New features** + +* Create and store AI memories to use as Agent Mode context. + +**Improvements** + +* Expanded Prompt Suggestions to cover more use cases. + +**Bug fixes** + +* Fixed Warp Prompt clipping issues encountered with certain fonts. +* Fixed inverse and double-underline cell styling not persisting through session restoration. + +### 2025.02.12 (v0.2025.02.12.16.51) + +**New features** + +* `CTRL-TAB` is now configurable under `Settings > Features` to cycle between the most recently used sessions rather than just activating the next tab. + +**Improvements** + +* The LLM menu is now keyboard-navigable. + +**Bug fixes** + +* Clearing Blocks now also clears any active Prompt Suggestions. +* Fix Kali Linux `.bashrc` breaking Warp. +* Fix bug with Agent Mode in PowerShell sessions with multi-line commands. +* Fixed a bug that prevented Autosuggestions from being accepted and Agent Mode model from being selected while up arrow history was open. +* Fixed cases where dragged Warp tabs would get stuck. +* Restores subshell Warpification script. +* \[macOS] Fix hotkey keybinding not triggering on non-US keyboard input source. + +### 2025.02.05 (v0.2025.02.05.08.02) + +**New features** + +* You can now talk to Warp to transcribe Agent Mode prompts or any other text! Set up the hotkey in `Settings > AI > Voice` or use the microphone button in AI input mode to trigger this. + +**Improvements** + +* Autosuggestions in the input now soft-wrap. +* You can now attach default environment variables to a workflow. + +### 2025.01.29 (v0.2025.01.29.08.02) + +**New features** + +* Added support for DeepSeek R1 and V3 in Agent Mode! Try them out by switching to Agent Mode and clicking on the model name in the prompt. +* Agent Mode can now auto-execute readonly requested commands. Commands can also be explicitly allowlisted or denylisted. See `Settings` -> `AI` -> `Autonomy` to configure. + +**Improvements** + +* You can now use `j`/`k` keys to navigate up and down Warp Drive. +* Agent Mode chip added to Warp prompt. +* Next Command is preferred over Command Corrections in cases where Corrections has less confidence. +* Moved the Settings modal to its own tab. + +**Bug fixes** + +* Fixed a bug that caused double-clicking to select the incorrect range of text when non-ASCII characters are present. +* Saving workflow aliases no longer deletes aliases from other workflows. +* Fixed cases where a small part of the bottom of the editor would be cut off at certain appearance settings. + +### 2025.01.22 (v0.2025.01.22.08.02) + +**New features** + +* Generate input for any interactive CLI using ⌘I on macOS and Ctrl-Shift I on Linux. +* You can now dynamically populate arguments in Workflows with shell commands. +* Added support for rectangular selection when holding ⌘⌥ on macOS and Ctrl-Alt on Linux. + +**Improvements** + +* Settings are now searchable and rendered in a separate tab +* Terminal font weight is now configurable. +* Launch Configurations now save the focused window state and active pane. +* Autosuggestions in the input now soft-wrap. + +**Bug fixes** + +* Fixed several issues where hovering over URLs in the blocklist sometimes resulted in URLs only being partially detected, or not detected at all. +* Fixed issue with Prompt Suggestions occasionally remaining visible after subsequent command execution. +* \[macOS] Changed the download location for new Warp updates to prevent corruption. + +### 2025.01.15 (v0.2025.01.15.08.02) + +**New features** + +* Font ligatures in grids! See setting under Settings > Appearance > Text to enable. +* You can now define aliases that expand to Warp Drive workflows. + +**Improvements** + +* Launch configurations now save focused tab state. +* Added support for Windsurf as an external editor. +* macOS-only: added a new AI app menu. + +**Bug fixes** + +* Fixed pane navigation when panes are not overlapping. +* Fixed a bug where Agent Mode LLM choices weren't populated correctly upon logging in. +* Fixed bug with drag-and-drop files causing duplicated filepaths. + +### 2025.01.08 (v0.2025.01.08.08.02) + +**New features** + +* A percentage of Warp users may now enable cloud syncing of their Warp settings under `Settings` > `Account`. We are gradually enabling this feature for all Warp users starting in this release. See the [documentation](https://docs.warp.dev/terminal/more-features/settings-sync) for more information. +* Introduced a setting to hide the tab bar (Zen mode). See the [documentation](https://docs.warp.dev/terminal/appearance/tabs-behavior) for more information. +* Introduced new profile menu. + +**Improvements** + +* Removed the Command Corrections banner, as there's already an autosuggestion in the input editor. +* Implemented `_`, `+`, and `-` motions in Vim mode. +* Warp will now show a warning before closing a session with a long-running process. +* Pasting multiple lines of content into the terminal's `Find` feature will convert it into a single line of text, rather than hide previous lines. +* Titles of notebooks imported from Markdown files no longer end in `.md`. +* "What's new" no longer shows on update. +* Added the ability to hide blocklist lines. +* Consolidated top bar navigation items. +* Settings are now in the profile menu. +* Scrollbars and pane controls only show on hover. + +**Bug fixes** + +* Fixed the rendering of keyboard shortcuts at larger font sizes. +* Tab completion menu now closes after selecting a single remaining suggestion. +* Warp displays an error if relaunching to apply an update failed. +* Old prompt suggestions won't reappear when issuing AI queries rapidly or after clearing the blocklist. +* Accepting the 'What happened here?' autosuggestion no longer clears AI context blocks. +* `alt` key now sends meta control codes to the shell in long-running blocks and the alt screen. +* When secret redaction is disabled, secrets are not redacted in command corrections. +* \[macOS] Fixed a bug where assigning `cmd-shift-left` and `cmd-shift-right` to an action sometimes wouldn't work. + +### 2025.01.02 (v0.2024.12.18.08.02) + +**Improvements** + +* We now immediately show an error when trying to Warpify unsupported shells over SSH. + +**Bug fixes** + +* Fixed blank lines being appended to some blocks on resize. +* Fixed an issue where the AI context disappears when accepting the default autosuggestion. + +### 2024.12.26 (v0.2024.12.18.08.02) + +**Improvements** + +* We now immediately show an error when trying to Warpify unsupported shells over SSH. + +**Bug fixes** + +* Fixed blank lines being appended to some blocks on resize. +* Fixed an issue where the AI context disappears when accepting the default autosuggestion. + +### 2024.12.19 (v0.2024.12.18.08.02) + +**New features** + +* Introducing: Next Command! Next Command uses AI to suggest the next command to run based on your active terminal session and command history. Visit Settings > AI to turn it off. +* Added support for block and underline-styled cursors in the input editor (while vim mode is disabled). + +**Improvements** + +* Clarified default permission information for sessions and Warp Drive objects. +* F11 (configurable) now toggles fullscreen on Linux and Windows. +* PowerShell environment variables are now recognized in completions. +* Cursor shape is now more responsive to clickable buttons. + +**Bug fixes** + +* Characters from unhandled keystrokes no longer handled as typed characters in the alt screen, e.g. when using vim. +* Fixed issue with copying secrets when secret redaction is disabled. +* kubectl completions now respect your kubeconfig, specified through environment variables or command line flag. +* ssh commands with permission issues should no longer suggest sudo. +* Fixed an issue with lazygit entering a blank screen. +* \[macOS] Fixed a bug where Warp disk images volumes might not be unmounted after an update. +* \[macOS] Improved robustness of autoupdate process. + +### 2024.12.13 (v0.2024.12.10.15.55) + +**New features** + +* Prompt Suggestions may appear above the input, helping you activate Agent Mode quickly in scenarios where it might be helpful. Note this feature sends activity to an LLM to generate prompts, head to Settings > AI > Agent Mode if you'd like to turn it off. +* Warp now has support for Claude 3.5 Sonnet and Haiku. Choose which model to use in the dropdown menu above your Agent Mode prompts. +* Agent Mode can now leverage your Warp Drive contents to tailor responses to your personal and team developer workflows. +* Warp has added a Shell Selector - a dropdown menu next to the 'New tab' button in the tab bar - to quickly pick from the shells available on your system. +* Agent Mode can now suggest code changes in a built-in code editor. +* \[macOS] You can now configure whether closing the last window quits the app (in Settings > Features). + +**Improvements** + +* Added settings to manage Warp's AI integration and permissions. Visit Settings > AI to learn more. +* Single-window launch configs can be launched into the active window from the launch config palette using cmdorctrl-enter. +* You can now set `PS1` with `PROMPT_COMMAND` in bash. + +**Bug fixes** + +* Fixed an issue where the 'Git Uncommitted File Count' prompt chip did not work on fish on Linux. +* Fixed highlighting for arguments in workflows with multibyte characters +* Hitting ENTER within the Launch Config Save Modal will work as expected. +* Fixed issue with copying secrets when secret redaction is disabled. + +### 2024.12.11 (v0.2024.12.10.15.55) + +**New features** + +* Prompt Suggestions may appear above the input, helping you activate Agent Mode quickly in scenarios where it might be helpful. Note this feature sends activity to an LLM to generate prompts, head to Settings > AI > Agent Mode if you'd like to turn it off. +* Warp now has support for Claude 3.5 Sonnet and Haiku. Choose which model to use in the dropdown menu above your Agent Mode prompts. +* Agent Mode can now leverage your Warp Drive contents to tailor responses to your personal and team developer workflows. +* Warp has added a Shell Selector - a dropdown menu next to the 'New tab' button in the tab bar - to quickly pick from the shells available on your system. +* Agent Mode can now suggest code changes in a built-in code editor. +* \[macOS] You can now configure whether closing the last window quits the app (in Settings > Features). + +**Improvements** + +* Single-window launch configs can be launched into the active window from the launch config palette using cmdorctrl-enter. +* You can now set `PS1` with `PROMPT_COMMAND` in bash. + +**Bug fixes** + +* Fixed an issue where the 'Git Uncommitted File Count' prompt chip did not work on fish on Linux. +* Fixed highlighting for arguments in workflows with multibyte characters +* Hitting ENTER within the Launch Config Save Modal will work as expected. + +### 2024.12.05 (v0.2024.12.03.08.02) + +**New features** + +* You can now share shared sessions directly with your Warp team, another Warp user, and non Warp users via a URL. +* You can now share Warp Drive objects directly with others via email or a URL. +* Padding in the alt-screen can now be manually adjusted. Defaults to no padding. + +**Improvements** + +* Improved PTY throughput by \~13% through more efficient dirty region computation. + +### 2024.12.02 (v0.2024.12.02.15.50) + +**Bug fixes** + +* Warp no longer uses so much CPU. + +### 2024.11.27 (v0.2024.11.27.01.55) + +**Improvements** + +* \[Agent Mode] Code outputs no longer show a confusing code diff UI. +* You can now sort Warp Drive objects by type, with folders on top. + +**Bug fixes** + +* \[Agent Mode] Single-line code suggestions are no longer hidden behind the horizontal scrollbar. +* Fixed a crash interacting with Env Vars in the command palette. + +### 2024.11.25 (v0.2024.11.25.16.32) + +**Improvements** + +* \[Agent Mode] Code outputs no longer show a confusing code diff UI. +* You can now sort Warp Drive objects by type, with folders on top. + +**Bug fixes** + +* \[Agent Mode] Single-line code suggestions are no longer hidden behind the horizontal scrollbar. +* Fixed a crash interacting with Env Vars in the command palette. + +### 2024.11.22 (v0.2024.11.22.18.28) + +**Improvements** + +* \[Agent Mode] Code outputs no longer show a confusing code diff UI. +* You can now sort Warp Drive objects by type, with folders on top. + +**Bug fixes** + +* \[Agent Mode] Single-line code suggestions are no longer hidden behind the horizontal scrollbar. +* Fixed a crash interacting with Env Vars in the command palette. + +### 2024.11.26 (v0.2024.11.19.08.02) + +**New features** + +* You can now use Warp without login! + +**Improvements** + +* \[Agent Mode] Code outputs no longer show a confusing code diff UI. +* You can now sort Warp Drive objects by type, with folders on top. + +**Bug fixes** + +* \[Agent Mode] Single-line code suggestions are no longer hidden behind the horizontal scrollbar. +* Fixed a crash interacting with Env Vars in the command palette. +* Fixed a bug where `command substitution: ignored null byte in input` would appear as output while using a Bash subshell. + +### 2024.11.19 (v0.2024.11.19.08.02) + +**New features** + +* You can now use Warp without login! + +**Improvements** + +* \[Agent Mode] Code outputs no longer show a confusing code diff UI. +* You can now sort Warp Drive objects by type, with folders on top. + +**Bug fixes** + +* \[Agent Mode] Single-line code suggestions are no longer hidden behind the horizontal scrollbar. +* Fixed a crash interacting with Env Vars in the command palette. + +### 2024.11.18 (v0.2024.11.18.16.37) + +**Improvements** + +* Added padding after an expanded Agent Mode requested command. +* Improved the quality of autosuggestions. +* Warp Drive workflow links now open in the active terminal session rather than a new tab. +* On the web, Warp Drive workflows now have a button to quickly open the workflow in Warp's desktop app. + +**Bug fixes** + +* Fixed Graphite CLI (`gt`) completions. +* Fixed completion and syntax highlighting behavior for arguments containing backslashes in PowerShell. +* Fixed an issue where opening Warp Drive in a browser could cause the tab to stop responding. + +### 2024.11.12 (v0.2024.11.12.08.02) + +**Improvements** + +* Added padding after an expanded Agent Mode requested command. +* Improved the quality of autosuggestions. +* Warp Drive workflow links now open in the active terminal session rather than a new tab. +* On the web, Warp Drive workflows now have a button to quickly open the workflow in Warp's desktop app. +* \[Linux] Increased the app icon size to match other apps. + +**Bug fixes** + +* Fixed Graphite CLI (`gt`) completions. +* Fixed completion and syntax highlighting behavior for arguments containing backslashes in PowerShell. +* Fixed an issue where opening Warp Drive in a browser could cause the tab to stop responding. +* \[Linux] Tightened timeout for looking up the system color scheme at app startup to avoid hangs if the `org.freedesktop.portal.Desktop` D-Bus service is unresponsive. +* \[macOS] Fixed a crash that can occur when starting the app or opening a new window. + +### 2024.11.11 (v0.2024.11.05.08.02) + +**Improvements** + +* Fixes a bug where Warpifying subshells could crash if you had something typed in your input. +* Renamed the Subshells tab to Warpify in Settings. + +**Bug fixes** + +* Fixed an issue where kubectl resource names wouldn't complete given a prefix. +* Fixed bug causing not all memory to be immediately freed when clearing the blocklist. +* \[macOS] Fixed a crash that can occur when starting the app or opening a new window. + +### 2024.11.05 (v0.2024.11.05.08.02) + +**Improvements** + +* Fixes a bug where Warpifying subshells could crash if you had something typed in your input. +* Renamed the Subshells tab to Warpify in Settings. + +**Bug fixes** + +* Fixed an issue where kubectl resource names wouldn't complete given a prefix. +* Fixed bug causing not all memory to be immediately freed when clearing the blocklist. + +### 2024.10.23 (v0.2024.10.29.08.02) + +**Bug fixes** + +* Improved command completions to no longer attempt to use error messages as valid options. +* Fixed some kubectl completions not working as intended. + +### 2024.10.17 (v0.2024.10.15.08.02) + +**New features** + +* Warp.dev has a fresh look today! Check out what's new and read about the design process behind the launch: [https://www.warp.dev/blog/world-of-warp](https://www.warp.dev/blog/world-of-warp) + +**Improvements** + +* Created a setting allowing focus to follow mouse hover (requested in issue [699](https://github.com/warpdotdev/warp/issues/699)). +* Automatically switch to shell command input mode if accepting a shell command autosuggestion from Agent Mode. +* \[macOS] Adjusted default font smoothing (Appearance > "Use thin strokes") configuration to improve text legibility. + +**Bug fixes** + +* Alt-screen find doesn't beachball when scrolling through find matches. +* You can now select individual cells in the alt-screen. +* All find matches are correctly highlighted in the alt-screen. +* Hitting ENTER within the Launch Config Save Modal will work as expected. +* Removed node prompt chip due to slow performance. +* Fixed an issue on Linux distributions where Warp took a long time to start up. + +### 2024.10.11 (v0.2024.10.08.08.02) + +**Improvements** + +* Tab key always accepts active autosuggestions in zero-state. +* Command suggestions from Agent Mode are now ghosted autosuggestions instead of direct buffer text. +* Warp now shows a warning when closing a tab with running commands or shared sessions. +* New Agent Mode panes will open to a useful minimum width if the Warp window is big enough to support it. +* Clearing the terminal input via ctrl-c will now also close the command search. +* \[macOS] You can now access Warp Drive features from mac menus. +* \[macOS] You can click the mouse middle-button to paste from the clipboard. + +**Bug fixes** + +* Agent Mode queries are now de-duplicated in up-arrow history and Command Search. +* `ctrl-d` can now be used to signal EOF when the shell is bootstrapping. +* Double-clicking the tab bar now correctly toggles maximizing the Warp window even when an AI block is present in the focused pane. +* Hovering over the block insertion menu at the bottom of a notebook no longer causes Warp to hang. +* Fixed crash when search result in alt screen is scrolled out of view. +* Fixed broken `cmd-shift-R`/`ctrl-shift-R` keybinding for accessing the Workflows view. + +### 2024.10.10 (v0.2024.10.08.08.02) + +**Improvements** + +* Tab key always accepts active autosuggestions in zero-state. +* Command suggestions from Agent Mode are now ghosted autosuggestions instead of direct buffer text. +* Warp now shows a warning when closing a tab with running commands or shared sessions. +* New Agent Mode panes will open to a useful minimum width if the Warp window is big enough to support it. +* Clearing the terminal input via ctrl-c will now also close the command search. +* \[macOS] You can now access Warp Drive features from mac menus. +* \[macOS] You can click the mouse middle-button to paste from the clipboard. + +**Bug fixes** + +* Agent Mode queries are now de-duplicated in up-arrow history and Command Search. +* `ctrl-d` can now be used to signal EOF when the shell is bootstrapping. +* Double-clicking the tab bar now correctly toggles maximizing the Warp window even when an AI block is present in the focused pane. +* Hovering over the block insertion menu at the bottom of a notebook no longer causes Warp to hang. + +### 2024.09.24 (v0.2024.09.24.08.02) + +**New features** + +* Powershell is now supported! Make `pwsh` your default shell for your user account or select `pwsh` in Settings > Features > Startup shell for new sessions. +* You can now save and sync environment variable collections in Warp Drive. To learn more, see [Environment Variables](https://docs.warp.dev/features/warp-drive/environment-variables). +* Your Agent Mode blocks and queries are now restored across sessions. + +**Improvements** + +* Secret redaction now applies to AI Blocks within Warp, in addition to Command Blocks. +* New Agent Mode panes always open to the right. +* You can now navigate the trash index via your keyboard. + +**Bug fixes** + +* `fish` config is no longer sourced twice during shell startup. +* The first window after launching Warp will now use a custom window size if set. +* When opening a launch configuration, Warp now respects restored and custom window sizes. + +### 2024.09.17 (v0.2024.09.17.08.02) + +**New features** + +* \[Linux] Warp now supports Wayland. You can configure the window system in `Settings > Features > System`. + +**Improvements** + +* Adds a Command Palette action called “Export all Warp Drive objects” that enables bulk export of a Warp Drive. +* Completion suggestions for git commit hashes are now sorted reverse-chronologically. +* History shows the working directory in which you made an Agent Mode query. +* Agent Mode Blocks are surfaced in Find. + +**Bug fixes** + +* Fixed an infinite loop bug that could lead to runaway memory usage and the application hanging. +* Fixes a regression where the Setup Guide didn't work. + +### 2024.09.05 (v0.2024.09.10.08.02) + +**Improvements** + +* Links are now detected in Agent Mode responses. + +**Bug fixes** + +* Fixed an infinite loop bug that could lead to runaway memory usage and the application hanging. + +### 2024.08.29 (v0.2024.08.27.08.02) + +**Bug fixes** + +* Link highlights now correctly disappear when making changes in alt-screen programs. + +### 2024.08.22 (v0.2024.08.20.08.02) + +**New Features** + +* You can now specify a cursor color in Warp themes. + +**Improvements** + +* Warp now restores fullscreen windows to fullscreen. + +**Bug fixes** + +* \[macOS] Completions for commands now work when you type a command name containing capital letters. This does not apply to aliases. + +### 2024.08.14 (v0.2024.08.13.08.02) + +**New Features** + +* New enums for Workflow arguments. Now you can set a list of suggested options for any argument in a workflow so it's easier to fill in parameters correctly. To learn more, see [Workflows](https://docs.warp.dev/knowledge-and-collaboration/warp-drive/workflows#working-with-arguments). + +### 2024.08.07 (v0.2024.08.06.08.01) + +**New Features** + +* You can now find your past Agent Mode queries in Command Search (ctrl-r). + +**Improvements** + +* Completions-as-you-type now works in AI input for filepath completions. + +**Bug Fixes** + +* Warp now recognizes more escape codes for toggling alternate screen mode. + +### 2024.07.30 (v0.2024.07.30.08.02) + +**Improvements** + +* Now it's easier to find and configure settings related to AI on the command line. You can enable / disable natural language detection or input hint text under Settings > AI + +### 2024.07.24 (v0.2024.07.23.08.02) + +**New features** + +* You can now find AI queries from other sessions in up-arrow history. + +**Improvements** + +* Clicking an attached block on an AI block no longer affects your pending query's context selection. +* Clicking the terminal input box will no longer remove the blocks you selected as context. +* Added support for smart selections in AI blocks. +* Increased priority of command matches when searching for a workflow. + +**Bug fixes** + +* Opening file links with line and column numbers in Zed now works. + +### 2024.07.19 (v0.2024.07.16.08.02) + +**Improvements** + +* Completions for git push origin now include tags in addition to branches. +* Docker extension: The "Open in Warp" feature now requires you to run the command in order to open the Warpified Docker subshell. Attempts to open an invalid link will display an error toast. + +**Bug fixes** + +* Warp prompt text now respects custom line height settings. +* Scroll positions are now stable when hitting block line limits ([1355](https://github.com/warpdotdev/warp/issues/1355)). +* Fixed binaries listed directly in `PATH` being automatically executed when running commands in Bash. + +### 2024.07.18 (v0.2024.07.16.08.02) + +**Improvements** + +* Completions for git push origin now include tags in addition to branches. +* Docker extension: The "Open in Warp" feature now requires you to run the command in order to open the Warpified Docker subshell. Attempts to open an invalid link will display an error toast. + +**Bug fixes** + +* Warp prompt text now respects custom line height settings. +* Scroll positions are now stable when hitting block line limits ([1355](https://github.com/warpdotdev/warp/issues/1355)). +* Fish commands containing syntax errors now correctly "finish" the block. +* Fixed binaries listed directly in `PATH` being automatically executed when running commands in Bash. + +### 2024.07.11 (v0.2024.07.09.08.01) + +**New features** + +* Same line prompt. Now you can choose whether you'd like your prompt on a new line (Warp's default) or on the same line with commands, like a classic terminal. If you're using PS1, Warp will use the same line prompt setting to respect theme configurations. Visit Settings > Appearance > Prompt to configure your prompt style. To learn more, see [Prompts](https://docs.warp.dev/terminal/appearance/prompt#same-line-prompt). + +**Improvements** + +* Added support for completions while using Agent Mode input. +* Semantic selection now works in AI blocks. +* Shift+click now lets you select text for alternate screen apps in SGR mouse mode. + +**Bug fixes** + +* Pressing Esc in Vim insert mode no longer closes the history menu. +* Made sure terminal context menus close when opening the settings modal. + +### 2024.06.27 (v0.2024.06.25.08.02) + +**New features** + +* Warp’s new Pro plan includes higher AI requests for individuals or small teams. +* Learn more at [https://www.warp.dev/blog/pro-plan](https://www.warp.dev/blog/pro-plan) + +**Bug fixes** + +* Text selection in full screen apps will change as you scroll. +* \[macOS] Meta shortcuts, e.g. `OPT-U`, `OPT-I`, will no longer be ignored. + +### 2024.06.21 (v0.2024.06.18.08.02) + +**Improvements** + +* The glyph over the cursor will take on a high-contrast color to make sure it's legible. +* Dragging a word or line selection in a notebook now extends the selection. + +**Bug fixes** + +* Fixes a crash where text layout would not expect the BOM marker at the beginning of a string. +* \[Linux] Fix middle-click paste doubling the text. + +### 2024.06.20 (v0.2024.06.18.08.02) + +**Improvements** + +* The glyph over the cursor will take on a high-contrast color to make sure it's legible. +* Dragging a word or line selection in a notebook now extends the selection. + +**Bug fixes** + +* Fixes a crash where text layout would not expect the BOM marker at the beginning of a string. + +### 2024.06.17 (v0.2024.06.11.08.02) + +**New features** + +* New Agent Mode in Warp AI: Use plain English on the command line to accomplish multi-step workflows. +* Learn more at [https://www.warp.dev/blog/agent-mode](https://www.warp.dev/blog/agent-mode) + +### 2024.06.13 (v0.2024.06.11.08.02) + +**Improvements** + +* Brackets and quotes are now autocompleted in the workflow editor. +* Improved support for editing multi-line workflows. + +### 2024.06.06 (v0.2024.06.04.08.02) + +**Improvements** + +* Warp now supports Unicode emoji presentation selectors when rendering glyphs +* Removed the default keybindings for Warp Drive object creation actions, in order to free up more keyboard shortcut options. You can still assign custom keybindings to these actions in Settings > Keyboard shortcuts + +**Bug fixes** + +* When editing with Vim visual line mode and the cursor is at the end of the line, operators will only affect the correct lines + +### 2024.05.30 (v0.2024.05.28.08.02) + +**Improvements** + +* Warp now renders terminal text ANSI colors as specified by the theme without any dimming + +### 2024.05.23 (v0.2024.05.21.16.09) + +**Bug fixes** + +* Fixed a bug where a terminal session could get stuck in a bad state if an SSH connection is lost while the alternate screen is in use (e.g.: tmux, TUI programs, pagers) +* Fixed a bug where 00\~ and 01\~ characters could get erroneously added to user-submitted commands after an SSH connection is lost + +### 2024.05.16 (v0.2024.05.14.08.01) + +**New features** + +* Team admins can now make their teams discoverable to colleagues from the same custom email domain. This feature is available under Settings -> Teams. + +**Bug fixes** + +* The prompt and command should no longer overlap the output (or each other) for multi-line commands in Bash versions earlier than 4.4--such as the default Bash installation for macOS. + +### 2024.05.09 (v0.2024.05.07.08.02) + +**Bug fixes** + +* Vim-related settings no longer appear in the Command Palette when editing with Vim keybindings is disabled +* Warp’s Input Editor now immediately reflects any changes to the Vim status bar settings +* Fixed a bug when handling URLs with parentheses in notebooks and Warp AI + +### 2024.05.02 (v0.2024.04.30.08.02) + +**Bug fixes** + +* In Notebooks, code block menus no longer overlap with rich text menus +* Fixed an issue that could cause Warp to display an invisible/empty window +* Fixed a crash that could occur when unindenting multiple lines within the Input Editor +* Fixed a Vim Mode bug when “cutting word left” (and similar actions) while the (up-arrow) history menu is open +* \[Linux] Fixed an issue where Warp would flicker on Intel UHD 620 drivers when using Vulkan due to a bug in specific versions of Mesa +* \[Linux] Fixed a regression in input latency + +### 2024.03.27 (v0.2024.04.23.08.01) + +**New features** + +* The free preview for Warp AI and Warp Drive for teams has ended. \[Learn about Warp’s new self-service plan] + +**Improvements** + +* Shared links to notebooks and workflows are now opened directly in Warp and no longer need to go through a browser + +**Bug fixes** + +* Warp now supports completions for directories that contain spaces when in a remote session +* Warp’s notebook editor now only shows hint text when it’s in edit mode + +### 2024.04.18 (v0.2024.04.16.08.02) + +**Improvements** + +* You can now navigate and expand folders in Warp Drive with left/right arrow keys + +**Bug fixes** + +* Middle-click now works even when the mouse is within the prompt area +* Already-open notebooks no longer open in a new tab +* Fixed an issue where autocd completions were incorrect for file paths starting with `~` +* Opening a Workflow through a link now focuses it, even while in trash view +* Fixed a bug handling carriage returns in notebooks, the markdown viewer, and Warp AI + +### 2024.04.11 (v0.2024.04.09.08.01) + +**Improvements** + +* Improved Warp’s prompt performance for large repositories +* When switching panes directionally, Warp now automatically selects the most recently focused pane in that given direction + +**Bug fixes** + +* Fixed a pane management bug where dragging a pane to a new location wouldn't initiate the option to drop it there + +### 2024.04.04 (v0.2024.04.02.08.02) + +**New features** + +* Notebooks in Warp Drive. Create and share interactive runbooks with your team. [Learn more](https://www.warp.dev/blog/notebooks-in-warp-drive) + +**Improvements** + +* You can now export workflows and notebooks from Warp Drive +* Middle-clicking to paste now automatically focuses the Input Editor +* Warp no longer automatically expands aliases that are escaped using a backslash +* \[Linux] Adds support for Android Studio, DataGrip, DataSpell, Goland, Pycharm, Rider, Rubymine, and Sublime Text as external editors + +**Bug fixes** + +* \[Linux] Warp now case-sensitively parses top-level commands on Linux +* \[Linux] Fixed an issue where middle-click paste could paste across multiple panes + +### 2024.03.21 (v0.2024.03.19.08.01) + +**Bug fixes** + +* Symlinks to a directory are now properly treated as a directory instead of as a file +* \[Linux] Warp's windows are no longer escalated into an urgent state (tiling window managers) after a Warp URL is opened + +### 2024.03.14 (v0.2024.03.12.08.02) + +**Improvements** + +* Warp now supports the primary selection protocol, which allows you to paste with a middle click. On platforms that don't support this, Warp will read/write from the default clipboard. +* You can now filter out unwanted lines from a block, using the new "invert filter" toggle in the block filtering menu +* Continuous block selections are now rendered with a single border instead of a border around each individual block +* The `` and `^` patterns are now supported in Warp's regex search (find bar and block filtering) +* \[Linux] The hotkey window now has a unique instance name on X11. + +**Bug fixes** + +* "Copy on Select" now works within alt-screens + +### 2024.03.07 (v0.2024.03.05.08.02) + +**Improvements** + +* You can now adjust the number of lines the mouse wheel scrolls in Warp. Go to Settings > Features > General > Lines Scrolled by Mouse Wheel Interval to configure this setting. +* You can now close the Warp window using the Command Palette (`SHIFT-CMD-W` for Mac). +* You can now quit Warp using the Command Palette (“Quit Warp”) +* \[Linux] Warp can now automatically hide the window's traffic lights when using a tiling manager +* \[Linux] Improved (a window’s) rounded corners when using a tiling manager +* \[Linux] You can now move tabs left or right using keyboard shortcuts. Use `SHIFT-CTRL-PGUP` to move a tab to the left and `SHIFT-CTRL-PGDN` to move a tab to the right + +**Bug fixes** + +* Fixed a bug where Warp could crash because of an invalid Vim command +* \[Linux] Fixed a bug where errors encountered while running `pacman-key` could lead to an invalid pacman repository configuration + +### 2024.03.05 (v0.2024.03.05.08.02) + +**Improvements** + +* Improved Warp's appearance and behavior when running in some tiling window managers. + +**Bug fixes** + +* Fixed crash that occurs when dragging the mouse. + +### 2024.02.29 (v0.2024.02.27.08.01) + +**Improvements** + +* Added completion support for `dnf` +* Configuring the global hotkey window settings (Quake Mode) now updates the window in real time +* \[Linux] Can now `CTRL-CLICK` to open a file +* \[Linux] Added support for IntelliJ, CLion, Webstorm, and PhpStorm + +**Bug fixes** + +* Fix issue with typeahead commands overlapping the prompt’s content +* Command X-Ray now recognizes builtins and functions, hover over a command in the Input Editor to see the command description +* Fixed an issue where the shell couldn’t accept pasted text when an rc file expected user input. +* \[Linux] Modified pacman-key -r invocation during Arch Linux auto-update to be more robust +* \[Linux] Fixed crash on Linux that could occur if device was missing a symlink from libX11.so to libX11.so.6 +* \[Linux] Fixed issues where opening external links would cause Firefox 123 to use 100% CPU and never launch +* \[Linux] X11 Users can now open links when default browser is firefox +* \[Linux] Fix some global hotkey combinations crashing the app. + +### 2024.02.26 (v0.2024.02.20.08.01) + +**New features** + +* Warp is now available for Linux! + +**Improvements** + +* Completions for apt-get, aptitude, and pacman +* You can now type to search in the font picker in Settings > Appearance + +### 2024.02.20 (v0.2024.02.20.08.01) + +**Improvements** + +* Completions for apt-get, aptitude, and pacman. + +### 2024.02.16 (v0.2024.02.16.17.24) + +**New features** + +* Warp on Linux (Private Beta): Added support for the Input Mode Editor (IME). + +### 2024.02.14 (v0.2024.02.14.15.46) + +**New features** + +* Warp on Linux (Private Beta): Added support for the Input Mode Editor (IME). + +### 2023.02.08 (v0.2024.02.13.08.02) + +**Bug fixes** + +* Fix the inputted command sometimes overlapping rprompt (right-sided prompt) + +### 2023.02.01 (v0.2024.01.30.16.52) + +**Improvements** + +* Improved UX for pasting an auth token to complete the sign-in flow +* Subversion (svn) information is now available in Warp's prompt + +### 2023.01.18 (v0.2024.01.16.16.31) + +**New features** + +* Warp on Linux (Private Beta): System fonts now load as expected + +**Bug fixes** + +* Warp on Linux (Private Beta): `ALT-TAB` no longer incorrectly inserts 4 spaces into the Input Editor + +### 2023.01.11 (v0.2024.01.09.08.02) + +**New features** + +* New workflow metadata for shared workflows in Warp Drive! Hover over any workflow to learn how recently the workflow has been executed, who edited it last, and when it was last edited. + +### 2023.12.21 (v0.2024.01.02.08.02) + +**Improvements** + +* The toolbelt displayed when hovering over background Blocks now has a solid background + +**Bug fixes** + +* The Markdown Viewer now respects the start number of ordered lists +* Completing a path that includes the tilde (`~`) character now works as expected +* Fixed an issue where Warp could quit before saving changes to Warp Drive +* Fix Warp hanging when using the 'Insert into Input' context menu action + +### 2023.12.14 (v0.2023.12.12.08.02) + +**New features** + +* Editing with Vim keybindings is now out of beta and generally available! Warp will detect vi mode in shell settings and suggest Vim keybindings. + +**Improvements** + +* You can now use `CMD-F` to search text in the Markdown Viewer + +**Bug fixes** + +* Block hover buttons now have a solid background when they overlap with your prompt +* The Block filter editor now has a clear button +* `J` and `K` (Vim Mode) can be used for navigation within a multi-line command +* Fixed the left alignment of the tab bar when in full-screen mode on macOS +* Fixed triple-click selection (selecting a line) when filtering a Block +* Fixed potential crash when using the find bar +* Fixed potential crash when retrieving accessibility contents +* Fix bug where "R" is erroneously inserted into the input in zsh sessions + +### 2023.12.07 (v0.2023.12.05.08.02) + +**Improvements** + +* Markdown file links can now be configured to open with the default external editor or Warp's built-in markdown viewer +* Warp Drive folders now keep their opened/closed state through app restarts + +**Bug fixes** + +* The Input Editor now refocuses correctly after pasting terminal contents and running a command +* Fixed issue with missing toolbelt buttons when using fish wih Vim Mode + +### 2023.11.30 (v0.2023.11.28.08.02) + +**Improvements** + +* Warp’s custom prompt builder now includes a context chip for Kubernetes context +* Improved completions for kubectl, including suggestions for resource, global options, and namespaces + +**Bug fixes** + +* Fixed a UI bug in the workflows editor where the editor for arguments was overflowing +* Search bar focuses as expected when you open Launch Configurations with the Command Palette + +### 2023.11.16 (v0.2023.11.14.08.02) + +**Bug fixes** + +* The informational block that shows workflow metadata now resizes with your Warp window +* The scrolling speed is now standardized across Warp + +### 2023.11.09 (v0.2023.11.07.08.02) + +**New features** + +* New Markdown Viewer: You can now open .md files in Warp and run the shell commands within these files +* Block Filtering: You can now filter block output (SHIFT-OPT-F) to quickly find matching lines based on a query. + +**Improvements** + +* Removed the workflow button from the toolbelt section (top-right buttons) of a block. It is still accessible through the right-click menu (see “Save as Workflow”) and its default keybinding CMD-S. +* Improved performance of Warp Drive team and state syncing + +### 2023.11.02 (v0.2023.10.31.08.03) + +**Improvements** + +* You can now invite new team members to your shared Warp Drive by email address and revoke invitations + +### 2023.10.23 (v0.2023.10.17.08.03) + +**Improvements** + +* Indicators appear in the tab bar when the current pane is maximized (a full-screen icon) and when a command exits with an error +* The Git context chip in Warp’s prompt now shows the commit hash instead of “HEAD” when in a detached state +* Easier to add and remove allowlisted domains when inviting teammates to Warp Drive +* Added a menu option for copying a workflow command (into the clipboard) + +### 2023.10.19 (v0.2023.10.17.08.03) + +**Improvements** + +* Indicators appear in the tab bar when the current pane is maximized (a full-screen icon) and when a command exits with an error +* The Git context chip in Warp’s prompt now shows the commit hash instead of “HEAD” when in a detached state +* Easier to add and remove allowlisted domains when inviting teammates to Warp Drive +* Added a menu option for copying a workflow command (into the clipboard) + +### 2023.10.12 (v0.2023.10.10.08.06) + +**Improvements** + +* Warp can now support macOS's proxy settings +* You can now toggle whether to render Warp using the integrated GPU for dual GPU Macs +* Warp now escapes the file path of an executable loaded from Finder + +**Bug fixes** + +* Fixed a crash on startup for some users on macOS Sonoma +* The workflow info box now refreshes when edited + +### 2023.10.05 (v0.2023.10.03.08.03) + +**New features** + +* Now you can use Vim keybindings to edit text on the command line in Warp. Navigate to Settings > Feature > Editor and enable "Edit commands with Vim keybindings." This feature is currently in beta and available to try today. + +**Improvements** + +* Admins can now control whether the team invite link is accessible for other team members to copy and share. Admins can also reset the URL token if needed. +* You can now add a 24-hour timestamp to your Warp prompt with context chips in the prompt editor. +* The free preview for Warp AI and Warp Drive for teams has been extended. [Learn More](https://www.warp.dev/blog/free-preview-extended) + +### 2023.09.28 (v0.2023.09.26.08.09) + +**New features** + +* If you have Cursor installed, you can now set this as your default code editor under Settings > Features > General. + +**Improvements** + +* Enhanced user accessibility by adding a tab bar button as a new entry point for the command palette. +* Improved user guidance by displaying a warning when attempting to run a workflow while another command is already in progress. + +**Bug fixes** + +* Resolved an issue where autosuggestions were not being inserted when bound to certain keybindings. +* Fixed a bug affecting Input Method Editor functionality on non-English keyboards, which caused incorrect positioning and prevented text input after opening a new window. + +### 2023.09.14 (v0.2023.09.19.08.04) + +**New features** + +* You can now edit keybindings to scroll up and down by one line. + +**Improvements** + +* The input editor remains visible in inactive panes when using split panes. + +**Bug fixes** + +* Resolved a regression where the filled bookmark icon didn’t display on bookmarked blocks unless hovered on. +* Fixed the `TAB` key not cycling through fields in the Workflow editor under certain circumstances. +* Restored functionality of the keybinding for “New Tab” to work even when no windows are open. + +### 2023.09.07 (v0.2023.09.06.18.09) + +**Improvements** + +* The new tab keyboard shortcut (`CMD-T` by default) can now be re-mapped. +* Warp Drive now shows a loading indicator when syncing. + +**Bug fixes** + +* The command timestamp tooltip is no longer hidden when the Input Editor is pinned to the top. + +### 2023.08.31 (v0.2023.08.29.08.04) + +**Improvements** + +* You can now delete custom themes from the Warp UI +* You can now scroll to the top or bottom of a selected block from the Command Palette. + +**Bug fixes** + +* Fixed an issue where CPU was being used up by git processes ([3563](https://github.com/warpdotdev/warp/issues/3563)) +* Fixed a Zsh bug where `set sh_word_split` could break Warp's bootstrapping + +### 2023.08.24 (v0.2023.08.22.08.03) + +**New features** + +* Secret Redaction - Warp can now automatically redact secrets and sensitive information in terminal output, including passwords, IP addresses, API keys, and PII. Enable Secret Redaction from the Command Palette or Settings > Privacy > Secret Redaction + +**Improvements** + +* Special keys used in conjunction with `META` e.g. `META-DELETE` should now work within the alt-screen +* The line height for the text within the Input Editor should now actually change when the custom height in `Settings > Appearance > Text > Line Height` is updated +* Alias Abbreviations in fish should no longer show a red error underline within the Input Editor +* Reduced the bottom padding within the Input Editor when Warp is in Compact Mode + +### 2023.08.17 (v0.2023.08.15.08.03) + +**New features** + +* Warp now displays richer metadata for each command in history, including exit code, working directory, git branch, and whether the command is part of a workflow. +* Warp's native prompt is now customizable directly within the app with drag-and-drop Context Chips (`Settings > Appearance > Prompt`) + +**Improvements** + +* Warp now supports xterm's escape codes (sequences) for focus reporting +* The Command Palette now supports searching for workflows with their Warp Drive folder name, in addition to the Workflow's name and description. +* Auto-generating custom themes from starting images now work even with a missing `~/.warp/themes` directory +* The "New Workflow" modal now supports more text for longer commands + +### 2023.08.10 (v0.2023.08.08.08.04) + +**New features** + +* Automatically create new themes based on a background image! Click the `+` button in the theme picker (`Settings -> Appearance -> Current Theme`) or search `Open Theme Picker` within the Command Palette + +**Improvements** + +* Workflows and folders in Warp Drive can now be sorted alphabetically and by last updated +* Multiple JetBrains IDEs are now supported as external editors (e.g. WebStorm, PhpStorm, GoLand) +* The Command Palette now shows which folders a Workflow is in (breadcrumbs) +* Aliases like `...` and `....` no longer incorrectly have an error underline + +### 2023.08.03 (v0.2023.08.01.08.05) + +**New features** + +* Reopen closed tabs with `SHIFT-CMD-T` for up to one minute; configure or disable this feature in `Settings > Features > Enable reopening of closed sessions` +* Autogenerate descriptions for Workflows in Warp Drive using Warp AI + +**Improvements** + +* Nested folders in Warp Drive can now be collapsed all at once +* Fixed issue where fish abbreviation expansion would include comments +* Fixed a regression with fish history becoming inaccessible + +### 2023.07.27 (v0.2023.07.25.08.03) + +**Improvements** + +* Fixed an issue where $PATH could be overwritten in Bash subshells +* Fixed an issue where completions for file-paths broke when using Named Flags e.g. `ls --color=auto` +* Fixed an issue where Warp Drive objects could get stuck in a sync state +* The down arrow `DOWN` now correctly moves the cursor within Warp AI's text editor + +### 2023.07.20 (v0.2023.07.18.08.03) + +**New features** + +* Can now configure whether `TAB` accepts autosuggestions or opens the completions menu; switch between the configurations via `Settings > Features > Editor` +* Improved completions behavior by improving common prefix detection, and supporting case sensitivity +* Can now natively draw some Unicode block element characters instead of using font glyphs--improves alignment and reduces fuzziness +* Warp's Resource Center now displays new features and improvements + +**Improvements** + +* Increased the maximum blur radius from 18 to 64 + +### 2023.07.13 (v0.2023.07.11.08.03) + +**New features** + +* Warp Drive items that failed to sync can now be retried +* Workflows in Warp Drive drive can now be edited with the workflow execution modal + +**Improvements** + +* Fixed a bug where git information could sometimes be missing from the prompt +* Adjusted some colors throughout Warp--replaced gradients with solid colors. + +### 2023.07.06 (v0.2023.07.04.08.03) + +**New features** + +* A new AI Command Search experience that allows you to translate natural language to shell commands and integrates directly with workflows! Type '#' in the input to try it out! + +**Improvements** + +* Fixed a bug where Warp was not recognizing some single character commands and aliases. +* Fixed a bug where command output would sometimes be cut off after finishing (most notably in Gradle). +* Fixed a bug where two prompts could appear for remote Bash sessions + +### 2023.06.29 (v0.2023.06.27.19.34) + +**New features** + +* App links of the form Warp://launch/\<launch\_configuration\_name> directly open a launch configuration +* Added a new setting for creating new windows with a specific size in terms of rows and columns. + +**Improvements** + +* Fix rendering of multiple ANSI styles on the same character. This fixes rendering issues commonly encountered in Vim and emacs. +* Fix tabs (indentations) sometimes being inserted into the Input Editor when the completion menu should open. +* Added tooltip for “New tab” button +* The “Launch Configurations” sub-menu (under the Mac File menu) now updates dynamically as launch configurations are added and removed. +* Find bar is able to match double-width unicode characters, including CJK and emojis. +* Fixed a crash that could occur when pasting a command in the workflow editor + +### 2023.06.20 (v0.2023.06.20.08.04) + +**New features** + +* You can now bring the power of your Powerlevel10k (P10K) prompt to Warp! For best results, you’ll need the latest version of P10K; see their GitHub page for upgrade instructions +* Right-side prompts are now supported in Zsh and fish! +* Warp AI commands can now be executed as workflows. + +**Bug fixes** + +* Clicking on an inactive Warp window now focuses the underlying pane correctly. + +### 2023.06.08 (v0.2023.06.13.08.03) + +**New features** + +* Added a settings page for our upgraded referral system--we’ve added new swag options. +* Right-click a highlighted file path to open a context menu that now supports showing the file in Finder +* The Command Palette can now search through Warp sessions, actions and launch configurations + +**Bug fixes** + +* The completions menu now supports fish abbreviations +* Fixed an issue where certain aliases would be incorrect after expansion. +* Fixed command search to ignore the extra whitespace before and after the search query +* Restored background Blocks no longer create blank history entries +* Fixed an issue where enabling the “Open completions as you type” setting could sometimes break path completions +* Fixed an issue where Zsh could fail to bootstrap when `$PATH` is an a bad state +* Fixed issue where Warp’s bootstrap logic could leak into Zsh’s history +* Fix issue with properly underlining when hyperlinks are in lists or span across multiple lines + +### 2023.06.01 (v0.2023.05.30.08.03) + +**New features** + +* Right-clicking the New Tab (`+`) button opens a context menu to select saved Launch Configurations +* Use Page Up (`PG-UP`) and Page Down (`PG-DOWN`) in the Command Palette for faster navigation +* Added support for Zed as a default code editor +* Referral counts have been updated to only include referrals who’ve onboarded onto (actually tried) Warp + +**Bug fixes** + +* Warp’s hotkey window (Quake Mode) now properly retains its size +* Fixed issue where command output would temporarily cutoff when resizing Warp. +* Fixed the Sticky Command Header covering content for pager commands. +* Fixed tabs showing stale text when being renamed. +* Clicking a Mac menu bar item that has a sub-menu no longer incorrectly closes the menu +* Warp now automatically focuses the shortcut search bar when the keyboard shortcuts pane is opened (`CMD-/`) +* Fixed regression where Warp’s native prompt no longer showed the virtual environment + +### 2023.05.25 (v0.2023.05.23.08.05) + +**Bug fixes** + +* Improved shell startup performance after a system restarts for users with Xcode installed +* Fixed issue with Warpifying a pipenv shell subshell from zsh +* Fixed issue with updating the git status prompt indicator in remote subshells + +### 2023.05.18 (v0.2023.05.18.01.08) + +**New features** + +* Warp now supports subshells in Zsh, Bash, and fish for a better experience with Docker, GCP, Poetry, and more. Configure which commands you’d like to “Warpify” under Settings > Subshells + +**Bug fixes** + +* Fixed an issue with Warp's completions when using flags that start with a single dash e.g. `-namespace` +* Fixed an issue with Synchronized Inputs where switching from alt-screens focused on the incorrect terminal session +* Fixed an issue where command history suggestions could cause Synchronized Inputs to get out of sync + +### 2023.05.11 (v0.2023.05.09.08.03) + +**New features** + +* Warp now sends the output of background shell processes into new (distinct) Blocks--separate from user generated Blocks. +* Synchronize (broadcast) input across multiple panes in a single tab or multiple tabs (`Mac Menu > Edit > Synchronize Inputs` or `Synchronize` within the Command Palette) +* Added option to enable (disabled by default) an audible terminal bell (`Settings > Features > Terminal` or “Enable/Disable Audible Terminal Bell” within the Command Palette) +* Now opens new windows with the same position and size of the most recently closed window (if there is one) +* Fish aliases are now supported in the completions menu + +**Bug fixes** + +* Support for `SHIFT-UP` and `SHIFT-DOWN` within alt-screen editors +* Fixed incorrect alt-screen scrolling behavior when scroll reporting is enabled +* `SHIFT-TAB` now (correctly) sends the ANSI (backward-tab) escape sequence (for Vim and NeoVim) +* SSH wrapper now also loads your /etc/profile and supports login-like prompts and interactions like printing the message of the day (MOTD) + +### 2023.05.04 (v0.2023.05.02.08.03) + +**New features** + +* Indicate when Warp is downloading an update in Settings > Account > About Warp +* Support alias expansion for bash/zsh aliases + +### 2023.04.27 (v0.2023.04.25.08.05) + +**New features** + +* Support for Fish abbreviations +* Right-click within the Input Editor to open a context menu where you can split panes, etc. + +**Bug fixes** + +* Starting a command with whitespace in the Workflow creation dialog no longer breaks its argument parser +* Fixed a bug when commands were aliased to `comm` because of a naming clash with Warp's wrapper +* `Cut word left` (`CTRL-W`) and `Cut word right` (`OPT-D`) now use the shell clipboard instead of the system clipboard + +### 2023.04.13 (v0.2023.04.11.08.03) + +**New features** + +* Navigation by subword within the Input Editor with `CTRL-OPT-LEFT` and `CTRL-OPT-RIGHT` +* View prior Warp AI questions using the `UP` arrow even after the transcript is cleared + +**Bug fixes** + +* Fixed a bug in proxied SSH while not on the default shell +* Background blur now also applies to windows that are opened via drag-and-drop from Finder +* The Sticky Command Header no longer cuts off text for pagers + +### 2023.04.06 (v0.2023.04.04.08.03) + +**New features** + +* The position of the input and direction of the terminal output are now configurable. You can start the input at the top and have it move down as new commands are run (to clear the screen and reset the position press `CTRL-L`, `CMD-K` or type `clear`). Or you can keep the input pinned to the top of the pane and have terminal outputs flow in reverse order. Settings are available under `Settings > Appearance > Input Position` +* Added a button for “jumping to the bottom” of the currently hovered Block to make it easy to get to the bottom of an output. Configurable with a setting under `Settings > Appearance > Blocks` +* Warp AI transcripts can now be navigated via keyboard (`UP` / `DOWN` arrows) +* Added a right-click context menu in the alt-screen (that still respects mouse reporting and SGR\_MOUSE) +* Warp AI's past prompts can be accessed via `UP` (arrow) +* `CMD-ENTER` within Warp AI now inputs the selected command into the Input Editor + +**Bug fixes** + +* Workflows can now be searched by their description in Command Search +* Consolidated “Ask Warp AI” keybindings into one +* Fixed an issue causing “Move cursor by word” and “Select left/right by word” to not work if “Left/Right Option key is Meta” is enabled +* Can now unset cursor navigation bindings within an executing command + +### 2023.03.30 (v0.2023.03.28.08.03) + +**New features** + +* Warning if a known-incompatible custom prompt is detected +* Keybindings for cursor navigation in REPLs and subshells, e.g. ⌥←, ⌥→, ⌥⌫, ⌘←, ⌘→, ⌘⌫, ⌘fn⌫ + +**Bug fixes** + +* Fixed an issue where an input suggestion tooltip could overflow outside the visible window +* Fixed keybinding conflict with Warp AI +* Fixed completion and syntax highlighting when local paths contain separators, not in the prefix + +### 2023.03.23 (v0.2023.03.21.08.02) + +**New features** + +* Added VSCode Insiders as a supported code editor +* Added completions for pnpm. + +**Bug fixes** + +* Fixed an issue where AI command results with multiple commands would all render on the same line +* The configurable width of Universal Search is now persistent (doesn’t reset to default in new sessions). +* “Copy Prompt” now correctly respects your PS1 prompt, if enabled +* Fixed automatic command corrections for cargo. + +### 2023.03.20 (v0.2023.03.14.08.03) + +**New features** + +* Added support to configure which shell Warp should use when starting a terminal session. Configurable under Settings -> Features -> Session. +* Tabs can now be renamed via mouse double-click. + +**Bug fixes** + +* Launch configuration templates now support use of `~` in the `cwd` field. +* Double-clicking a button/tab in the title bar no longer resizes the whole window. +* Context menus in the blocklist are now more pronounced and easier to dismiss by clicking. +* Increased the clickable area of small search boxes. +* A keyboard shortcut can now be registered to clear all blocks. +* Fixed some locale-related issues due to use of `LC_ALL` environment variable. +* Xterm escape code OSC 4 (“change color”) no longer crashes the app when it appears in PS1. +* Fixed a crash that occurs when resizing windows after dismissing a notification banner. +* Fixed crash that occurs if you unset the keybinding for the keyboard shortcuts side panel. +* Added Warp AI to resource center. + +### 2023.03.16 (v0.2023.03.07.08.02) + +**New features** + +* Introducing Warp AI ⚡ Get explanations for errors and outputs, ask for help with complicated workflows and scripts, easily execute suggested commands, all without leaving Warp! + +### 2023.03.09 (v0.2023.03.07.08.02) + +**New features** + +* Added support for clearing a keybinding for an action [2300](https://github.com/warpdotdev/warp/issues/2300). +* Added support for showing/hiding Warp windows with a system-wide Activation hotkey [2585](https://github.com/warpdotdev/warp/issues/2585). +* Improved scroll speed for Sidebar menu 'Warp Essentials'/'Keyboard Shortcuts' [2673](https://github.com/warpdotdev/warp/issues/2673). +* Users may now set a custom keybinding to open the completions menu. +* Enabling/disabling mouse reporting is no longer bound to CMD-R by default. +* Toggling mouse reporting enabled shows a banner. + +**Bug fixes** + +* Fixed SSH wrapper hanging forever when SSH host is Arch Linux with the latest bash package [2636](https://github.com/warpdotdev/warp/issues/2636). +* Fixed Bash commands having escape codes in the last 20 characters producing incorrect output. +* Fixed a bug with bash prompt expansion on recent macOS versions. + +### 2023.02.28 (v0.2023.02.28.08.03) + +**New features** + +* Warp now suggests a URL for creating a GitHub PR on `git push`. +* Command Search and Workflow menus are now horizontally resizable. + +**Bug fixes** + +* Fixed a bug where Warp doesn’t correctly Auto-Raise. +* Fixed issue where formatting is lost when pasting into nano. +* Fixed issue where Warp doesn’t detect process termination when exiting `info`. +* Fixed a bug with bash prompt expansion not working on v4.4 or earlier. +* Fixed a bug where profile pictures don’t show in the Account menu. +* Fixed Syntax Highlighting and Error Underlining’s handling of multi-byte characters. +* Fixed issue where 'Checking for Update’ doesn’t reflect the current status. + +### 2023.02.23 (v0.2023.02.21.08.03) + +**New features** + +* Support for configuring the initial working directory for new sessions. New tabs/windows/split panes can have separate configurations, or you can set one value for all new sessions. + +**Bug fixes** + +* Warp now supports syntax highlighting and error underlining for multi-line inputs with multibyte characters +* Fixed a bug where the update status in Warp’s `About Section` was incorrect. +* Improved GPU memory consumption when multiple windows are open. + +### 2023.02.16 (v0.2023.02.14.08.05) + +**New features** + +* Improved double-click selection. Double-clicking text now smart selects patterns like file paths, URLs, email addresses, etc. - [659](https://github.com/warpdotdev/warp/issues/659) +* Warp can now be opened from Finder - [102](https://github.com/warpdotdev/warp/issues/102) + +**Bug fixes** + +* Warp no longer hangs after exiting the alt-screen--having searched for text using Find. +* The Block-list now scrolls to the correct position after returning from the alt-screen. +* Clicking above the scroll-bar no longer (incorrectly) changes its scroll position. +* The terminal cell dimensions now update immediately after modifying the Font size. +* Hyperlinks no longer incorrectly highlight on hover when Warp is not focused. +* The Input Method Editor (non-English keyboards) is now positioned correctly in the alt-screen and in running Blocks +* When there are no windows open, clicking `New Tab` from the Mac menu will create a new window + +### 2023.02.09 (v0.2023.02.07.08.03) + +**Bug fixes** + +* Warp now sets the Mac window title; right-clicking on the dock icon will show the name of the active tab. +* Fixed a bug where navigating the theme picker with the arrow keys would lead to a crash when no theme matches the search. +* The Input Editor now refocuses correctly after clicking hyperlinks. +* Custom keybindings incorporating the `SPACE` key now persist after closing Warp. +* The Input Method Editor (non-English keyboards) now positions itself within the Input Editor + +### 2023.01.26 (v0.2023.01.24.08.03) + +**New features** + +* Warp can now dim inactive terminal panes, navigate to `Settings > Appearance > Panes > Dim inactive panes` + +**Bug fixes** + +* Fixed crash when selecting multiple occurrences of multi-byte characters using `CTRL-G` + +### 2023.01.19 (v0.2023.01.17.08.03) + +**New features** + +* The current Git branch can now be copied using the Command Palette (`CMD-P`) + +**Bug fixes** + +* Fixed bug where some keybinding actions would be applied to the wrong terminal pane. +* Warp now checks the input values for font size and line height and ignores them if they are too small or large +* The `missing update permissions banner`, can now be dismissed +* Fixed a rare crash when closing panes created by a launch configuration + +### 2023.01.12 (v0.2023.01.10.08.02) + +**New features** + +* Support setting window background transparency and blur radius, via sliders under `Settings > Appearance` +* Revamped resource center! Click the Warp icon in the top right to see keyboard shortcuts and learn how to best use Warp +* Quit modal: Quitting or closing Warp while a session is running triggers a warning prompt–that also lets you view which sessions are running +* Added a toggle to disable cursor blinking + +**Bug fixes** + +* Can now support completions that have escaped paths +* Can now support background images with paths that start with \~ +* Can now properly restore a Warp window’s position when using multiple monitors +* Commands from restored sessions run on the local machine no longer appear in the SSH server’s history +* Fixed issues SSHing into RHEL/Fedora machines with PackageKit-command-not-found installed +* Fixed incorrect handling of `->` as the user's prompt +* Fixed ls completions when using the --color option + +### 2023.01.05 (v0.2023.01.03.08.03) + +**Bug fixes** + +* Trailing periods are no longer considered part of a URL. +* Fixed regression where the "autocomplete symbols" setting was not being respected. + +### 2022.12.15 (v0.2022.12.13.08.04) + +**New features** + +* You can now reorder and drag tabs around with your mouse! + +**Bug fixes** + +* The welcome Block now also works when using Fish shell. +* AI Command Search no longer crashes from multi-byte characters when opened via the `#` prefix +* Warp no longer crashes when starting a new session in a deleted or inaccessible directory +* Resolved rendering bugs and hangs in full-screen applications like 'k9s' and 'less'. +* Added a login failure notification. + +### 2022.12.06 (v0.2022.12.06.08.03) + +**New features** + +* Users may now opt out of telemetry (app analytics and crash reporting) +* Added 'Tail Warp network log' workflow for viewing logs of all app network activity. + +**Bug fixes** + +* Full-screen CLI commands like mitmproxy now correctly span the entire view. +* Improved styling and organization of Features page in settings. +* Completions While Typing menu closes while generating new results. +* Added a hidden completion result for root dir. +* Warp now consumes less memory when a session has many blocks. +* Fixed an issue over SSH where logs were being inserted into input. + +### 2022.12.02 (v0.2022.11.29.08.03) + +**New features** + +* Users may now opt out of telemetry (app analytics and crash reporting) +* Added 'Tail Warp network log' workflow for viewing logs of all app network activity. + +**Bug fixes** + +* Mitigated an issue where running a command over SSH would emit spurious output (specifically, 'channel: open failed' statements) in a block. + +### 2022.12.01 (v0.2022.11.29.08.03) + +**New features** + +* Warp now supports using the find bar within the alt-screen! `CMD-F` now opens find within vim, less, and other alt-screen apps! + +**Bug fixes** + +* Respect symlinks in Warp configuration directories (for themes and workflows). +* Fixed unwanted text appearing in the Input Editor when RPROMPT is set +* Fixed the emoji composer not working properly. +* Fixed a crash that could occur when using the Unicode Hex Input keyboard. +* Fixed escape binding not closing the resource center +* Move Backward/Forward One Word bindings can now be overridden. +* Fixed crash when hovering over multiple byte text within the Input Editor +* Fixed “command not found: sed” and “command not found: tr” issues with the SSH wrapper. +* Fixed issue where tab completions and command search could be visible at the same time. + +### 2022.11.15 (v0.2022.11.14.14.55) + +**New features** + +* Command Search: Ctrl-R opens a panel where you can search your history, workflows, and other command execution-related items, all in one place. +* Sticky command header: Warp now pins the prompt/command section of a Block to the top of the screen; click it to scroll to the top of the Block. Can be toggled via Settings > Features > Show Sticky Command Header +* Warp’s Input Editor now supports soft wrapping; long commands are now fully visible! + +**Bug fixes** + +* Warp now sets the TERM\_PROGRAM environment variable correctly in wrapped SSH sessions. + +### 2022.11.10 (v0.2022.11.08.08.07) + +**New features** + +* Warp now offers Command Corrections! Warp will suggest corrections for errors in previous console commands +* Warp now also detects invalid file paths -- they are underlined red when error underlining is enabled +* Added a toggle in `Settings > Appearance` to configure whether and how Warp enforces minimum contrast + +**Bug fixes** + +* Fixed an issue where toggling the default prompt would not update it immediately +* Improved positioning of the `TAB` completions menu when using split panes + +### 2022.11.03 (v0.2022.11.01.08.03) + +**New features** + +* Warp's prompt now shows the number of modified files on your local git branch! Search "changed file count" in the Command Palette or right-click the Prompt to toggle. + +**Bug fixes** + +* Dim-styled colors are now restored properly. + +### 2022.10.27 (v0.2022.10.25.08.06) + +**Bug fixes** + +* Fixed a bug when hovering over hover icons + +### 2022.10.20 (v0.2022.10.18.08.10) + +**Bug fixes** + +* Modifying the mouse and scroll reporting settings now applies immediately +* Fixed cursor not blinking when starting a shell instance +* Fixed temporarily flashing the wrong prompt while Warp is still bootstrapping +* Removed duplicate entry for toggling error underlining and syntax highlighting within the Command Palette + +### 2022.10.13 (v0.2022.10.11.08.13) + +**New features** + +* Warp’s Input Editor now has Syntax Highlighting and Error Underlining, with no configuration! +* Warp now uses a pointer cursor when hovering over links + +**Bug fixes** + +* Git branches in the completions menu now bold correctly +* Warp no longer crashes when `/bin/bash` is missing + +### 2022.10.06 (v0.2022.10.04.08.05) + +**New features** + +* Drag and drop a folder or file onto the Warp dock icon to open a new tab in this directory +* Added dividers between Blocks in compact mode +* Shell keywords are now supported for completions and Command Inspector + +**Bug fixes** + +* Accessibility support for context menu keybinding +* Keystrokes typed while a command is still executing no longer gets dropped +* Link recognition no longer includes trailing quotes +* Find search results will continue to be highlighted after clearing the screen during a long running command +* Fixed completions for commands prefixed with environment variables +* Warp’s resource center is now center aligned + +### 2022.09.29 (v0.2022.09.27.08.11) + +**New features** + +* Extend the currently selected text (within Blocks) with `SHIFT-LEFT`, `SHIFT-RIGHT`, `SHIFT-UP`, and `SHIFT-DOWN` +* Double-click and drag to select text in the Input Editor +* Insert the last word of the previous command with `META-.` +* Added a toggle to enable mouse and scroll reporting to the settings dialog (`Settings > Features`) + +**Bug fixes** + +* The `clear` command no longer appears in the snackbar at the top of the window +* Warp’s completions now support executables in remote sessions (no longer just bash) +* Fixed subcommand completions for commands with proper prefixes of each other (e.g. `npm r` and `npm run`) +* The completion spec for `lsd` now supports files + +### 2022.09.22 (v0.2022.09.20.08.08) + +**New features** + +* After selecting a Block press `CTRL-M` to open its context menu +* Commands in the tab completions menu and history menu can now be executed directly with `CMD-ENTER` +* Completions now support shell builtins, git aliases, and also npm aliases + +**Bug fixes** + +* Command Palette now includes the most useful features at the top +* Improved flag completions for cargo + +### 2022.09.15 (v0.2022.09.13.08.15) + +**New features** + +* Warp Resource Center - explore Warp features and documentation by clicking the `?` icon or pressing `SHIFT-CTRL-?` +* New icons in the completion menu denoting flags, folders, branches, etc. + +**Bug fixes** + +* Press `CMD-ENTER` within the history menu (`CTRL-R`) to directly execute the highlighted command +* Fixed crash when opening many tabs (due to macOS's default open file descriptor limits) +* Fixed crash when laying out RTL text + +### 2022.09.08 (v0.2022.09.07.14.56) + +**New features** + +* Global hotkey window can now float above full-screen apps +* Tabs can now have their color customized (via right-clicking on a tab) +* Terminal line height is now configurable (via Settings > Appearance) + +### 2022.09.01 (v0.2022.08.31.18.11) + +**New features** + +* Tab completions now support fuzzy string matching +* Improve completions for over 450 commands, including docker, kubernetes, cargo, node, and git + +**Bug fixes** + +* Properly send C0 control codes for \<ctrl-\[2-8]> keystrokes +* Session restoration now also persists bold, underline, italic, and strikethrough formatting +* Inspect mode now works for the changelog modal +* Fixed a crash when highlighting a link +* Fixed Find occasionally returning only partial results +* Fixed occasional crash when loading images +* Fixed display issue in the Mac Menu for keyboard shortcuts with special keys + +### 2022.08.25 (v0.2022.08.23.08.06) + +**New features** + +* Experimental feature: support for always-on completions — the completions menu can now open automatically while typing (enable via Settings -> Features) + +**Bug fixes** + +* Custom tab titles no longer get overwritten when using multiple panes +* A Block’s execution duration is now formatted in hours, minutes, and seconds +* Improved rendering of the ‘Current session’ text in the Navigation Palette +* Warp properly hides the cursor when a CLI sends the respective escape sequence +* Warp stays focused (keyboard-interactive) after closing the Share Block menu and the context menu +* Warp no longer lags when the Ctrl-R menu is opened +* Confirming a tab suggestion appends a space to the buffer + +### 2022.08.18 (v0.2022.08.16.10.16) + +**New features** + +* Launch Configurations - Save a configuration of windows, tabs, and panes to open later with `CTRL-CMD-L` +* Session Navigation - Navigate to any session in Warp with `SHIFT-CMD-P` +* Added exclusive theme for users who joined Warp through a referral + +**Bug fixes** + +* Prompt now shows Git SHA instead of HEAD when you’re not on a branch +* Filepath completions now include current directory ('.') and parent directory ('..') +* Support `SHIFT-HOME` and `SHIFT-END` keybindings to select text to line start and end. +* Items in the Command Palette now highlight when you hover over them with your mouse +* Improved how Warp cleans up the warptmp directory for Zsh SSH sessions +* Already open dropdown menus are now properly closed when clicked +* Warp no longer crashes when dragging a window that’s running htop +* Warp no longer crashes when the find bar is open + +### 2022.08.10 (v0.2022.08.08.09.21) + +**New features** + +* Can now Middle-click a tab to close it +* Added additional tab reordering options (Close: tab, other tabs, and tabs to the right) via the Mac Menu, the Command Palette, and a tab’s context menu (right click) + +**Bug fixes** + +* Added a toggle to the Mac Menu for maximizing panes +* Can now switch panes using keyboard shortcuts even when a pane is maximized +* Add support for opening file paths with RubyMine, PhpStorm, and WebStorm +* Fixed crash when highlighting links +* Fixed issue where the HISTCONTROL environment variable was ignored in bash +* Pressing `CTRL-R` to open history search no longer crashes Warp when you have multiple cursors + +### 2022.08.03 (v0.2022.08.01.09.12) + +**New features** + +* Updated Mac menus to make Warp actions more discoverable - [101](https://github.com/warpdotdev/warp/issues/101) +* Warp now supports opening file links and urls via CMD-CLICK! - [177](https://github.com/warpdotdev/warp/issues/177) + +**Bug fixes** + +* Various CLI tools no longer hang e.g. Bazel and Maven +* Command Inspector hover no longer crashes with UTF-8 encoded strings +* Opening the find / search bar (`CMD-F`) now automatically selects the text +* Tab titles are no longer reset when changing panes + +### 2022.07.27 (v0.2022.07.25.09.05) + +**Bug fixes** + +* Closing and re-opening the Command Palette now resets the selected item +* The cursor’s position is now restored after exiting the Command History Search (`CTRL-R`) menu. +* Shorthand and longhand flags are now correctly surfaced (based on the number of dashes) in tab completions +* Added voiceover support for `BACKSPACE` and `DELETE` keystrokes within the Input Editor + +### 2022.07.20 (v0.2022.07.18.09.06) + +**New features** + +* Command Inspector - hover over any piece of a command in Warp’s Input Editor to surface documentation or press `CMD+I` to inspect at the cursor’s current location +* Improved ordering in the tab completions menu + +**Bug fixes** + +* Font color for links in light mode (themes) now set correctly +* Moving forward by a word no longer moves farther than expected +* Warp no longer hangs when passing an invalid file path +* Fixed issues with persisting the selected theme when “Sync with OS” is enabled and the theme picker is launched from the Command Palette (or a keyboard shortcut) +* Fixed issues with text input after clearing Blocks (`CMD-K`) while in a REPL environment. +* Fixed shortcut for select-left-by-word (`SHIFT-CMD-B`), select-right-by-word (`SHIFT-CMD-F`), select-line-to-end (`SHIFT-CTRL-E`), and select-line-to-start (`SHIFT-CTRL-A`) + +### 2022.07.13 (v0.2022.07.11.09.11) + +**Bug fixes** + +* Improved startup time for Fish shells +* Find Bar no longer crashes on selected text +* Scrollbar now supports jumping to where you click +* Fixed a bug with the referral link for sharing Warp not loading + +### 2022.07.07 (v0.2022.07.04.09.08) + +**New features** + +* Bookmark a Block (or multiple) for quick access via the scroll-bar +* Added a referral counter to the Settings > Account screen and the referral screen +* Added support for rendering text with a lower visual weight; enable the thin strokes option in Settings > Appearance (enabled by default for low-DPI displays) +* Togglable settings, overflow menu items, and settings pages are now accessible through the Command Palette +* CLI options are now surfaced by default without needing to type '-' +* Press SHIFT-CMD-C while in VSCode (Visual Studio Code) to open a new Warp session + +**Bug fixes** + +* Fixed referal links and share by email +* Fixed a hang that would sometimes occur when connecting with SSH +* Now support requesting media permissions (camera, audio, etc) +* Correctly parse Git commit SHAs in completion menus +* Improved tab completion support for command line arguments that are behind flags + +### 2022.07.06 (v0.2022.07.04.09.08) + +**New features** + +* Bookmark a Block (or multiple) for quick access via the scroll-bar +* Added a referral counter to the Settings > Account screen and the referral screen +* Added support for rendering text with a lower visual weight; enable the thin strokes option in Settings > Appearance (enabled by default for low-DPI displays) +* Togglable settings, overflow menu items, and settings pages are now accessible through the Command Palette +* CLI options are now surfaced by default without needing to type '-' +* Press SHIFT-CMD-C while in VSCode (Visual Studio Code) to open a new Warp session + +**Bug fixes** + +* Fixed a hang that would sometimes occur when connecting with SSH +* Now support requesting media permissions (camera, audio, etc) +* Correctly parse Git commit SHAs in completion menus +* Improved tab completion support for command line arguments that are behind flags + +### 2022.06.29 (v0.2022.06.27.09.14) + +**Bug fixes** + +* Cursor changes when hovering over clickable UI elements and the Input Editor +* Dim colors now render correctly + +### 2022.06.27 (v0.2022.06.20.09.15) + +**New features** + +* Improved auto-focus behavior when closing panes by keeping track of history when navigating or clicking around panes +* Performance improvements when executing Blocks: Warp no longer flashes on every command! + +**Bug fixes** + +* Input Editor re-focuses after renaming a tab +* Reduced visual weight of the active tab title to improve legibility. +* Improved blending along the inside edge of rounded corners +* Global Hotkey Windows (Quake Mode) now correctly respect the active screen setting +* Completions for flag arguments now support absolute and relative file paths (when applicable) +* Git checkout <`TAB`> now also completes branches with the remote prefixed. +* Pressing Arrow-up (`UP`) when the Input Editor is non-empty opens the command history with prefix filtering +* Button to copy app version moved to main settings page + +### 2022.06.22 (v0.2022.06.20.09.15) + +**New features** + +* Improved auto-focus behavior when closing panes by keeping track of history when navigating or clicking around panes +* Performance improvements when executing Blocks: Warp no longer flashes on every command! + +**Bug fixes** + +* Input Editor re-focuses after renaming a tab +* Reduced visual weight of the active tab title to improve legibility. +* Improved blending along the inside edge of rounded corners +* Global Hotkey Windows (Quake Mode) now correctly respect the active screen setting +* Completions for flag arguments now support absolute and relative file paths (when applicable) +* Git checkout <`TAB`> now also completes branches with the remote prefixed. +* Pressing Arrow-up (`UP`) when the Input Editor is non-empty opens the command history with prefix filtering +* Button to copy app version moved to main settings page + +### 2022.06.17 (v0.2022.06.13.09.15) + +**New features** + +* Added keyboard shortcuts to reorder tabs (CTRL-SHIFT-LEFT and CTRL-SHIFT-RIGHT) + +**Bug fixes** + +* Warp no longer crashes on macOS 13 (Ventura) +* Global Hotkey Window (Quake Mode) no longer overlaps Spotlight, Raycast, Alfred, and the macOS Dock +* Now correctly display the user and hostname in the Prompt after exiting an SSH session +* Fixed a memory leak on window close. + +### 2022.06.15 (v0.2022.06.13.09.15) + +**New features** + +* Added keyboard shortcuts to reorder tabs (CTRL-SHIFT-LEFT and CTRL-SHIFT-RIGHT) + +**Bug fixes** + +* Global Hotkey Window (Quake Mode) no longer overlaps Spotlight, Raycast, Alfred, and the Mac Dock +* Now correctly display the user and hostname in the Prompt after exiting an SSH session +* Fixed a memory leak on window close. + +### 2022.06.08 (v0.2022.06.06.09.05) + +**New features** + +* Now support renaming tabs (right click on your tab title!) +* Now support enabling custom prompt from prompt context menu (right-click on prompt) +* Now support splitting panes (left and right) from the context menu (right click) and through the Command Palette +* Now support CTRL-Click as an alternative to right-clicking + +**Bug fixes** + +* Improved completions support for arguments nested under options (e.g. git branch -D \<branch\_name...>) +* Modified files are now included (in addition to commit SHAs) for `git diff` + +### 2022.06.01 (v0.2022.05.30.09.10) + +**New features** + +* Added information about rewards to the referral screen +* Added a button that toggles regex search in the Find Bar +* Added completion support for shell functions + +**Bug fixes** + +* Hotfix - a regression that caused Warp to stall when using nano +* Improved kerning (font rendering) throughout the app +* Added a hyperlink (to our changelog history) in the Changelog modal +* Multiline commands that don't have any output are no longer cut off + +### 2022.05.26 (v0.2022.05.23.09.07) + +**New features** + +* Warp can now send you desktop notifications for long-running commands and password prompts - [628](https://github.com/warpdotdev/warp/issues/628) +* Added keybinding to toggle fullscreen mode + +**Bug fixes** + +* Stopped prepending \ before \~ in tab titles for older versions of Bash +* Added support for CMD-G and SHIFT-CMD-G to tab between results in the Find Bar + +### 2022.05.18 (v0.2022.05.16.09.01) + +**New features** + +* Added exclusive theme available to anyone who has referred someone to Warp. (Open Theme Picker > Warp Referral to use it) + +**Bug fixes** + +* Improved rendering of rounded corners throughout the app +* Fixed cell dimension computation for some fonts +* Fixed labels rendering incorrectly in the font selector dropdown in settings +* Fixed Bash remote sessions missing tab titles +* Reduced UI flickering after executing commands +* Fixed errors when sshing into remote machines which do not have xxd available +* Fixed some anti-aliased glyphs getting clipped during rasterization +* Fixed search bar stealing focus after command execution + +### 2022.05.11 (v0.2022.05.09.09.06) + +**New features** + +* Filepath completions without needing to cd +* Support for any font (not just monospaced) + +**Bug fixes** + +* Tab completions (cd) with international characters are now properly escaped (edited) +* Improve rendering performance when many tabs are open (fixes non-responsiveness when searching history) +* Fixed a race condition with autoupdate a11y announcements and other a11y messaging +* Fixed a regression that would cut off the output of some long-running Blocks + +### 2022.05.04 (v0.2022.05.02.09.00) + +**New features** + +* Added default tab titles for Bash +* Improved default tab title in Zsh +* Maximize a split pane +* Support rcfiles that check PS1 to determine if it's an interactive shell; this may explain missing aliases or commands in Warp! + +**Bug fixes** + +* History now correctly shows results after hitting ESC when a Block is focused +* Fixed crash when quitting AI Command Search while a command was being generated +* Global keybindings with function keys and numeric keys are now properly registered +* Warp no longer jumps up and down for single-line commands that take more than 50ms + +### 2022.05.02 (v0.2022.04.25.09.59) + +**New features** + +* Added a Quake Mode setting that configures whether Warp should automatically hide when losing focus - [1077](https://github.com/warpdotdev/warp/issues/1077) +* Added a Quake Mode setting that configures which screen to pin Warp on - [862](https://github.com/warpdotdev/warp/issues/862) +* Expanded the keybindings supported by Quake Mode / Global Hotkey Window - [856](https://github.com/warpdotdev/warp/issues/856) + +**Bug fixes** + +* Commands prepended with space are now stored in history if hist\_ignore\_space option is not set +* Now support dotfile configurations with non-English quotation marks +* Continued improving the reliability of login and auth within the app +* Improved performance for commands with large outputs +* Improved performance for long running commands +* Improved text alignment within inline banners + +### 2022.04.27 (v0.2022.04.25.09.59) + +**New features** + +* Added a Quake Mode setting that configures whether Warp should automatically hide when losing focus - [1077](https://github.com/warpdotdev/warp/issues/1077) +* Added a Quake Mode setting that configures which screen to pin Warp on - [862](https://github.com/warpdotdev/warp/issues/862) +* Expanded the keybindings supported by Quake Mode / Global Hotkey Window - [856](https://github.com/warpdotdev/warp/issues/856) + +**Bug fixes** + +* Commands prepended with space are now stored in history if hist\_ignore\_space option is not set +* Now support dotfile configurations with non-English quotation marks +* Continued improving the reliability of login and auth within the app +* Improved performance for commands with large outputs +* Improved performance for long running commands +* Improved line height computation for some fonts +* Improved text alignment within inline banners + +### 2022.04.20 (v0.2022.04.18.09.08) + +**New features** + +* Support logging into Warp by pasting the auth url when "Take me to Warp" fails in browser + +**Bug fixes** + +* Improved reliability of login and auth within the app +* Buttons within the find bar are now properly shaded for gradient themes +* Workflows with default values are now registered by Warp +* Fixed bootstrapping bug that affected Fish versions older than 3.2.0 +* Fixed a memory leak that occurred when new tabs were opened or panes were split + +### 2022.04.15 (v0.2022.04.11.09.09) + +**Bug fixes** + +* Support parsing PS1’s exit codes (Bash’s $?) and improved PS1 parsing for newer Bash versions (4.4+) +* Fixed prompt showing up as exit in Bash - [793](https://github.com/warpdotdev/warp/issues/793) +* Improved parsing of Zsh default prompts +* Opening the find bar will automatically select any existing text - [831](https://github.com/warpdotdev/warp/issues/831) + +### 2022.04.13 (v0.2022.04.11.09.09) + +**Bug fixes** + +* Support parsing PS1’s exit codes (Bash’s $?) and improved PS1 parsing for newer Bash versions (4.4+) +* Fixed prompt showing up as exit in Bash - [793](https://github.com/warpdotdev/warp/issues/793) +* Improved parsing of Zsh default prompts +* Opening the find bar will automatically select any existing text - [831](https://github.com/warpdotdev/warp/issues/831) + +### 2022.04.08 (v0.2022.04.04.09.07) + +**Bug fixes** + +* Block sharing dialog now scrolls properly + +### 2022.04.01 (v0.2022.04.01.01.37) + +**New features** + +* Warm welcome! +* A.I. Command Search + +**Bug fixes** + +* Warp now properly registers `SPACE` and `SHIFT` modifier keys for Global Hotkey Windows +* Page Up and Page Down keys now work correctly in vim and other fullscreen apps - [560](https://github.com/warpdotdev/warp/issues/560) +* SSH now supports bootstrapping if bash-preexec is included in a Debian VM’s system rcfiles (eg by default at Google) - [578](https://github.com/warpdotdev/warp/issues/578) +* Corrected keyboard shortcut for split pane in context menu + +### 2022.03.30 (v0.2022.03.29.02.23) + +**New features** + +* Workflows: an easier way to share, parameterize, and execute commands - [625](https://github.com/warpdotdev/warp/issues/625) +* Quake mode / Focus Warp with a Global Hotkey - [091](https://github.com/warpdotdev/warp/issues/091) + +**Bug fixes** + +* Magnet, Swish and ALT-Tab window managers now work with Warp - [776](https://github.com/warpdotdev/warp/issues/776) +* SSH now handles control master connection errors - [578](https://github.com/warpdotdev/warp/issues/578) +* SSH now handles verbose mode, no longer leaks into the Input Editor as a typeahead - [578](https://github.com/warpdotdev/warp/issues/578) +* SSH now boots normally for POSIX shells that aren’t supported by Warp’s wrapper - [578](https://github.com/warpdotdev/warp/issues/578) + +### 2022.03.24 (v0.2022.03.23.22.10) + +**New features** + +* Fish support - [190](https://github.com/warpdotdev/warp/issues/190) +* Basic screenreader support (Voiceover) - Warp is now an accessible terminal! +* Added a toggle in the settings to disable the SSH wrapper - [821](https://github.com/warpdotdev/warp/issues/821) + +**Bug fixes** + +* Hitting tab with a text selection shows tab completions instead of indenting +* SSH no longer hangs when /tmp is not writable for Zsh - [578](https://github.com/warpdotdev/warp/issues/578) +* SSH no longer bootstrap the shell if it’s not meant to be an interactive session (e.g. if -T or a command is passed) - [578](https://github.com/warpdotdev/warp/issues/578) +* SSH now supports Starship and Zsh's $PROMPT variable - [803](https://github.com/warpdotdev/warp/issues/803) +* Also import themes in subdirectories e.g. `~/.warp/themes/subdirectory/theme.yaml` + +### 2022.03.16 (v0.2022.03.14.08.49) + +**New features** + +* Multi-block selections and corresponding actions - [146](https://github.com/warpdotdev/warp/issues/146) +* Case-sensitive search + +**Bug fixes** + +* SSH no longer returns 0\~ and 1\~ after executing commands for Zsh 5.0.8 or older - [578](https://github.com/warpdotdev/warp/issues/578) +* SSH now supports LocalCommand / RemoteCommand - [578](https://github.com/warpdotdev/warp/issues/578) +* SSH over Zsh no longer depends on configuring locales on the remote machine - [578](https://github.com/warpdotdev/warp/issues/578) +* SSH sources /etc/bash.bashrc which is an extra rcfile in Debian and other Linux distributions - [578](https://github.com/warpdotdev/warp/issues/578) +* Improved completions stability when there are multiple panes on the same remote machine +* Vim and other alt-screen apps properly expand to take up the full window - [552](https://github.com/warpdotdev/warp/issues/552) +* Clicking into Warp from other foreground window focuses the clicked pane - [739](https://github.com/warpdotdev/warp/issues/739) +* Warp now respects ignore-space history options for Zsh and Bash - [044](https://github.com/warpdotdev/warp/issues/044) +* Warp now creates a \~/.warp folder to persist custom keybindings - [801](https://github.com/warpdotdev/warp/issues/801) + +### 2022.03.09 (v0.2022.03.07.08.51) + +**Bug fixes** + +* Added missing actions to Command Palette +* Option is meta is now in the settings menu +* Fix for SSH hanging when Zsh is the remote login shell +* Fix for SSH with Zsh that would break with certain rcfiles because of incorrectly set ZDOTDIR + +### 2022.03.02 (v0.2022.02.28.08.45) + +**New features** + +* Can now edit the keybindings for arrow navigation (Up/Down/Left/Right) +* Can now edit the keybindings for activating specific tabs (by number CMD-1, CMD-2, …) + +**Bug fixes** + +* Crash in theme chooser +* Fix for tab completion sometimes deleting characters + +### 2022.02.23 (v0.2022.02.21.08.55) + +**New features** + +* Zsh support over SSH +* Partially complete autosuggestion (by word) using CTRL-RIGHT and ALT-RIGHT - [488](https://github.com/warpdotdev/warp/issues/488) +* Added a Copy URL menu item after right-clicking a URL - [154](https://github.com/warpdotdev/warp/issues/154) +* Indicator for conflicting keybindings in keyboard customization UI + +**Bug fixes** + +* Able to fill-in longest common prefix after filtering tab completions - [618](https://github.com/warpdotdev/warp/issues/618) +* Block completion causes Input Editor to steal focus from find bar - [452](https://github.com/warpdotdev/warp/issues/452) +* UP-arrow in history menu sometimes scrolls more than one item +* CMD-F opens a no-op find bar in alt screen + +### 2022.02.16 (v0.2022.02.14.08.44) + +**New features** + +* Customizable key bindings (accessible via the settings menu) - [579](https://github.com/warpdotdev/warp/issues/579) +* Users can opt in to use their shell’s prompt rather than Warp’s default (select the Honor PS1 toggle under the settings menu) - [580](https://github.com/warpdotdev/warp/issues/580) +* Added a timestamp showing Block runtime duration; hover to see start and end date + time - [178](https://github.com/warpdotdev/warp/issues/178) +* CTRL-F now accepts autosuggestions - [403](https://github.com/warpdotdev/warp/issues/403) +* CTRL-E and CMD-RIGHT accept autosuggestions when at the end of the buffer - [403](https://github.com/warpdotdev/warp/issues/403) +* Allow input height to expand to half the pane height - [621](https://github.com/warpdotdev/warp/issues/621) + +**Bug fixes** + +* Arrow key presses now (up and down now) cycle themes in the theme picker - [294](https://github.com/warpdotdev/warp/issues/294) +* ESC keypress now exits the theme picker +* CMD-Down when on most recent block to focus input now clears Block selection +* Fixed a bug where resizing a pane while a command was running made it impossible to scroll to the bottom of the pane +* Fixed a bug where resizing a pane could cause Warp to show a blank screen +* Parentheses, quotes, and brackets now also auto-close after typing an alphanumeric character +* Remapped multi-cursor key bindings to CTRL-SHIFT-UP and CTRL-SHIFT-DOWN - [374](https://github.com/warpdotdev/warp/issues/374) +* Restored OPT-CMD-UP and OPT-CMD-DOWN for switching panes up and down - [730](https://github.com/warpdotdev/warp/issues/730) + +### 2022.02.02 (v0.2022.01.31.09.03) + +**New features** + +* Multi-cursor keybindings for adding cursors above and below current selections with OPT-CMD-UP/DOWN - [374](https://github.com/warpdotdev/warp/issues/374) + +**Bug fixes** + +* Double clicking the top of the window maximizes the app - [097](https://github.com/warpdotdev/warp/issues/097) +* Icon, cursor and selection contrast fixes +* Scrolling performance improvements with bg image themes +* Changelog visual glitch +* Resize bug - losing scroll position when viewing blocks with long output + +### 2022.01.26 (v0.2022.01.24.08.55) + +**New features** + +* Auto-close symbols (parentheses, quotes, and brackets) like VSCode + +**Bug fixes** + +* Block sharing link no longer cuts off - [660](https://github.com/warpdotdev/warp/issues/660) +* Right clicking a Block now focuses that Block +* Mouse dragging in vim +* Restoring history bug on session restore +* Automatically focus the last active window on session restore + +### 2022.01.19 (v0.2022.01.17.08.48) + +**New features** + +* Restore block contents +* The longest common prefix in the completions menu auto-fills the Input Editor - [479](https://github.com/warpdotdev/warp/issues/479) +* Add description for paths in completion results - [103](https://github.com/warpdotdev/warp/issues/103) +* Can right click the prompt and copy: git branch, prompt, cwd - [346](https://github.com/warpdotdev/warp/issues/346) + +**Bug fixes** + +* Fixed bug where venv was inserted into input editor - [599](https://github.com/warpdotdev/warp/issues/599) +* Improved url detection + +### 2022.01.12 (v0.2022.01.10.17.24) + +**New features** + +* Added a Changelog page to our documentation + +**Bug fixes** + +* Double clicking text in a url now highlights the word instead of the whole url - [508](https://github.com/warpdotdev/warp/issues/508) +* Double clicking a string with underscores now selects the whole string and not just the subword +* Selection updates correctly when a block hit its max line length +* Can now also close the Command Palette using CMD-P - [184](https://github.com/warpdotdev/warp/issues/184) +* Moved check for update button to settings dialog - [070](https://github.com/warpdotdev/warp/issues/070) +* Fixes tabs not opening in new windows when autoupdate is pending +* Fix regression with input box not being focused on app relaunch + +### 2022.01.05 (v0.2022.01.03.09.07) + +**New features** + +* Native undo and redo in the text editor using CMD-Z - [113](https://github.com/warpdotdev/warp/issues/113) +* Added CMD-M to minimize the Window - [107](https://github.com/warpdotdev/warp/issues/107) +* Added our open source licenses to the Warp Documentation +* Split pane focus indicator - a triangle in the top left corner of the pane in focus + +**Bug fixes** + +* CTRL-SPACE is now properly passed to Emacs and other terminal apps - [499](https://github.com/warpdotdev/warp/issues/499) +* Copy on select setting persists across sessions and does not reset after updates + +### 2021.12.29 (v0.2021.12.27.09.04) + +**New features** + +* Find in block (+ other find improvements) + +### 2021.12.22 (v0.2021.12.20.09.04) + +**New features** + +* Windows, tabs, and panes are restored whenever you reopen Warp. Restoring block content is on its way! +* Warp now supports completions for over 300 commands and more information about existing commands by using Fig’s completion specs +* Git aliases are now included in completions menu - [210](https://github.com/warpdotdev/warp/issues/210) +* Switch to next pane and previous pane with CMD-\[ and CMD-] - [392](https://github.com/warpdotdev/warp/issues/392) +* Scrolling the Block list with PG-UP and PG-DOWN - [370](https://github.com/warpdotdev/warp/issues/370) +* Copy and paste the file directory into Warp from Finder - [514](https://github.com/warpdotdev/warp/issues/514) +* When the last Block is selected, can re-focus the input editor using CMD-DOWN key +* Arrow down scrolls to bottom of last block + +**Bug fixes** + +* Copying selected text to clipboard creates a new entry for each selected character - [504](https://github.com/warpdotdev/warp/issues/504) +* Needed an extra backspace to escape CTRL-R / history menu - [427](https://github.com/warpdotdev/warp/issues/427) +* VIM performance improvements - we’ve made progress but would love more sample cases of slowness + +**Updates to Mac Menu Bar (Window)** + +* Zoom +* Minimize +* Tile Window to Left of Screen (Default) +* Tile Window to Right of Screen (Default) +* Move to X screen (Default) +* Enter Full Screen (Default) +* Bring All to Front + +### 2021.12.15 (v0.2021.12.13.08.40) + +**New features** + +* Fuzzy search in CTRL-R and Command Palette +* When you share a link to a block, up to 5 recipients may now download Warp’s beta via the link + +**Bug fixes** + +* Fix bug where opening file:// urls would not include query params like '?foo=bar' - [426](https://github.com/warpdotdev/warp/issues/426) +* More prominent highlights in CTRL-R, Command Palette, tab completion +* Vim bug fixes and performance improvements - please let us know what else you see + +### 2021.12.08 (v0.2021.12.06.19.09) + +**New features** + +* Added a send invite button in account section of the settings dialog +* You can now request more invites in the invite modal + +**Bug fixes** + +* Copy on select persistence bug +* UI Bug when trying to un-share a block - [439](https://github.com/warpdotdev/warp/issues/439) + +### 2021.12.01 (v0.2021.11.29.18.59) + +**New features** + +* Added 15 extra invites for everyone! +* Copy on select (highlighting text will automatically copy to clipboard). This can be turned off in the settings dialog - [077](https://github.com/warpdotdev/warp/issues/077) +* CTRL-L shortcut to clear the screen - [049](https://github.com/warpdotdev/warp/issues/049) + +**Bug fixes** + +* Can now highlight and copy sections of a URL without it automatically opening - [138](https://github.com/warpdotdev/warp/issues/138) + +### 2021.11.24 (v0.2021.11.23.17.55) + +**New features** + +* Background images + gradients in themes: You can now set a background image or gradient as your theme background. Warp ships with a few of these already or you can create your own via a yaml file. - [032](https://github.com/warpdotdev/warp/issues/032) +* Changelog dialog +* Emoji rendering: 😂, 😃, 🌍, 🍞, 🚗, 📞, 🎉, ❤️ - [075](https://github.com/warpdotdev/warp/issues/075) +* Improved settings dialog +* Theme search - [237](https://github.com/warpdotdev/warp/issues/237) + +**Bug fixes** + +* Properly escapes whitespace when you drag and drop files + +### 2021.11.17 (v0.2021.11.16.20.05) + +**New features** + +* Drag and drop files & directories from finder - [069](https://github.com/warpdotdev/warp/issues/069) + +### 2021.11.10 (v0.2021.11.09.19.46) + +**New features** + +* Autosuggestions: Warp now suggests commands as you type, similar to Fish or Gmail - [052](https://github.com/warpdotdev/warp/issues/052) +* Button to copy the app/version - [106](https://github.com/warpdotdev/warp/issues/106) +* Conda context to the prompt - [235](https://github.com/warpdotdev/warp/issues/235) + +**Bug fixes** + +* Conda info (prompt) locking input editor +* CTRL-D now deletes forward one character +* History now preserved across sessions - [337](https://github.com/warpdotdev/warp/issues/337) +* Enter (numpad) was inputting as CTRL-C - [330](https://github.com/warpdotdev/warp/issues/330) + +### 2021.11.03 (v0.2021.11.02.00.38) + +**New features** + +* CJK (Chinese, Japanese, and Korean) character support - [327](https://github.com/warpdotdev/warp/issues/327) +* Autocompletions for missing tar commands +* Enforcement of minimum contrasts in grid - [249](https://github.com/warpdotdev/warp/issues/249) + +**Bug fixes** + +* Runaway memory usage (from font loading on initial run) - [232](https://github.com/warpdotdev/warp/issues/232) +* Directories with non-english filenames not rendering on screen - [309](https://github.com/warpdotdev/warp/issues/309) +* App crashes from missing current working directory +* Pure Prompt being inserted as a typehead into editor - [242](https://github.com/warpdotdev/warp/issues/242) + +### 2021.10.27 (v0.2021.10.25.22.47) + +**New features** + +* Ability to unshare blocks in settings modal +* Link to the documentation in kebab menu (three dots in top right corner) + +**Bug fixes** + +* Double character entry after input editor loses focus + +### 2021.10.20 (v0.2021.10.19.21.38) + +**New features** + +* Switch theme based on OS appearance - [068](https://github.com/warpdotdev/warp/issues/068) +* Toggles instead of buttons in the setttings! +* Link to Custom themes documentation in the settings + +**Bug fixes** + +* IME support (non-English keyboards are now better supported in input box!) +* Show a banner instead of a popup when app startup takes longer than expected +* git log (and similar commands) no longer treated as a failed block + +### 2021.10.13 (v0.2021.10.12.19.34) + +**Bug fixes** + +* Shell Bootstrapping should be a lot faster +* Support 3-char color representation for hex colors in theme +* Fix crashes relating to reading history files +* Prevent block completion from stealing focus +* Fix broken click handling for showing and hiding overflow menu + +### 2021.10.06 (v0.2021.10.05.20.07) + +**Bug fixes** + +* Split pane navigation when 'Left / Right Option is Meta' settings are enabled +* Crash when opening a new window + +### 2021.09.29 (v0.2021.09.29.13.26) + +**New features** + +* Split panes: create multiple panes in the same tab via shortcuts (CMD-E/SHIFT-CMD-E), the Command Palette, or by right clicking in any pane. +* Custom themes via files. You can now define your own theme as a yaml file in \~/.warp/themes. For more information on the file format and to see \~100 of the most popular themes already implemented in this format, see [https://github.com/warpdotdev/themes](https://github.com/warpdotdev/themes). The ability to add and share themes directly within Warp is coming soon! + +**Bug fixes** + +* Add better messaging when Warp does not have permission to autoupdate +* Crash if a tab completion result was accepted after the cursor was moved to the beginning of the editor + +### 2021.09.22 (v0.2021.09.21.20.54) + +**New features** + +* Theme picker available from the Command Palette + +**Bug fixes** + +* Occasional crash when opening a new Warp window +* Font selection dropdown didn't respect theme choice +* Issues with padding and hover detection when toggling Compact Mode on or off + +### 2021.09.15 (v0.2021.09.14.21.25) + +**Bug fixes** + +* Crash when closing full-screen window +* Executables in path were not appearing for completions in Bash +* Completions menu overlaps theme picker + +### 2021.09.09 (v0.2021.09.09.0.0) + +**New features** + +* New themes for Warp!!! (Access them via Settings on the overflow menu. We have Dracula, Solarized, & Gruvbox) +* CMD-, opens the Settings menu + +**Bug fixes** + +* Fixed crash when we fail to load a font or when we scroll through fonts +* Fixed visual artifacts around windows and modals jumping +* Fixed crash that occurs when you CMD-F while selecting an already selected text + +### 2021.08.31 (v0.2021.08.31.0.0) + +**New features** + +* Support emacs bindings in input box +* History up menu performs a prefix search based on input + +**Bug fixes** + +* Warp not rendering after executing long-running command +* Stop powerlevel10k instant prompt from hanging on bootstrap +* Changing “font-size” via CTRL-- and CTRL-0 should stay in sync with font size in settings menu +* Bracketed paste mode bug: 0\~ \~1 on every command when ssh-ing +* Crash when tab completing with multibyte characters +* Download page doesn’t render correctly on safari +* Login is broken for some users using Chrome +* Make it more prominent in onboarding that we are collecting telemetry during the beta + +### 2021.08.25 (v0.2021.08.25.0.0) + +**New features** + +* Custom fonts +* Completions for aliases and environment variables + +**Bug fixes** + +* Completions loose ends, including completions for path names with spaces and if commands are separated by && +* Function key support within running programs (such as htop) +* Editor text respects zoom level +* Regression that caused URLs to not be highlighted +* Opening a new window required Internet connection + +### 2021.08.18 (v0.2021.08.18.0.0) + +**New features** + +* Re-run with sudo + +**Bug fixes** + +* Crash caused by pressing CMD-K +* Completion not working when cursor is mid-line +* Re-input of multi-line commands +* [084](https://github.com/warpdotdev/warp/issues/084) - Rendering of colors correctly in diffs +* Selection showing after closing and re-opening alt-screen + +### 2021.08.09 (v0.2021.08.09.0.0) + +**New features** + +* New settings modal (accessible from the top right overflow button) to set font size, toggle between light mode and dark mode, compact mode and normal mode +* CTRL-U and CTRL-K now cut to clipboard +* Typeahead: characters you type in a long-running command will now show up in the input box when the command completes + +**Bug fixes** + +* Handle arrow keys with modifiers (option and command) in CLIs and full-screen apps (Previously, users were unable to navigate with option and command keys in - Postgres CLI) +* Straightening the text baseline +* Translucent colors (e.g. for diff-so-fancy) are now correct (We now support the full range of opacity) +* Dotfile path completions + Completions improvements for more commands +* Artifacts when rendering svgs, especially on low res monitors. Overflow menu looks a lot better now! + +### 2021.07.28 (v0.2021.07.28.0.0) + +**New features** + +* Compact Mode (see GIF below) +* Support for mouse events in Vim and other programs that can handle mouse input +* Completions for npm / yarn scripts + +**Bug fixes** + +* Major improvements to the consistency of completions, especially for commands that can take multiple arguments (e.g. rm -rf) +* Proper path completions for absolute paths +* Hang when PROMPT\_COMMAND is set for the shell +* Context Menu not closing when clicking outside of the menu +* Crashes after executing multi-line commands and on older versions of macOS + +### 2021.07.21 (v0.2021.07.21.0.0) + +**New features** + +* Support for numpad ENTER +* More npm & yarn completions + +**Bug fixes** + +* Down arrow sends unrecognized escape sequence to Github CLI +* Can’t use UP arrow if item in history is multiple lines +* Crash when closing a tab when there are multiple tabs +* File-only completion signatures should also show directories + +### 2021.07.13 (v0.2021.07.13.0.0) + +**New features** + +* New invite system to add users to Warp. To invite new users, click the overflow menu at the top right and click 'invite users'. For now we ask that you please don't post these invites on social media! +* URLs in the terminal screen are auto-linkified +* Double clicking the title bar maximizes/minimizes the window + +**Bug fixes** + +* Various Command Palette bugs +* Find box is populated with the user's text selection +* 3 second latency when changing the prompt upon first SSHing + +### 2021.07.07 (v0.2021.07.07.0.0) + +**New features** + +* Command Palette for most keyboard shortcuts (CMD-P) +* Previously, tab completion descriptions were cut off. Now we display them in a floating box +* You can now switch tabs using CTRL-TAB and CTRL-SHIFT-TAB + +**Bug fixes** + +* Intermittent crashes with Zsh sessions and switching tabs +* Always fall back to path suggestions for completions +* Various bugs related to completions + +### 2021.06.29 (v0.2021.06.29.0.0) + +**New features** + +* Multiple window support +* New completions UI and in-line documentation for commands and flags +* Horizontal scrolling of input box to support long commands + +**Bug fixes** + +* Crash when exiting from logout or exit when there’s a background process +* Crash when bootstrapping from detecting incorrect shell name +* Various bugs related to completions + +### 2021.06.15 (v0.2021.06.15.19.04) + +**New features** + +* Mac File and Edit menus, along with Mac standard menu items (although New Window not yet working) + +**Bug fixes** + +* Crash when closing last window +* CMD-F: when there are no matches, display 0/0 +* CMD-F should not scroll away if navigating to a match on the same row +* CMD-F: render the yellow rectangle at the layer of rendering the cell +* Unable to move cursor upwards on multi-line previous command +* Warp bootstrap commands showing up in history over ssh +* Accept input via input box before terminal has bootstrapped +* New tab button should have hover and click state +* Output stops midway through session on iMac running Mojave 10.14.6 +* Backspace doesn’t work while holding shift +* Clipping issue in share dialog +* Input suggestions closes if you click on the scrollbar +* Hitting up/down while input suggestions are open causes menu to move +* Paste is not working for full screen apps +* Underline does not render with Hack font + +### 2021.06.09 (v0.2021.06.09.15.14) + +**New features** + +* SSH support (Warp now works the same when you SSH as it does locally!) +* Improved completions: we’ve built out new completions support that are snappier and have more intelligent suggestions for options and arguments for some of the most used commands +* Find: Pressing CMD-F now brings up a find view to search for text in the terminal + +**Bug fixes** + +* Text rendering was faded on certain monitors diff --git a/src/content/docs/code/code-editor/code-editor-vim-keybindings.mdx b/src/content/docs/code/code-editor/code-editor-vim-keybindings.mdx new file mode 100644 index 0000000..34b4195 --- /dev/null +++ b/src/content/docs/code/code-editor/code-editor-vim-keybindings.mdx @@ -0,0 +1,147 @@ +--- +title: Code Editor Vim Keybindings +description: >- + Use Vim keybindings in Warp's code editor for keyboard-driven navigation and + editing. +--- + +## About Vim keybindings + +The Vi family of programs (including Vim and Neovim) are modal text editors that allow for keyboard-driven text editing. Vi-style keybindings are especially popular among developers for their speed and precision in navigating and manipulating code. Warp’s [code editor](/code/code-editor/) now includes native support for Vim keybindings (also known as Vim mode), offering a familiar editing experience directly within your coding workflows. + +### How to enable Vim keybindings + +Vim mode in the code editor uses the same setting toggle as the input editor. To enable: + +* Through the [Command Palette](/terminal/command-palette/), search for "Vim Keybindings". +* Through **Settings** > **Features** > **Text Editing**, toggle "Edit code and commands with Vim keybindings". + +Unlike the input editor, the Vim implementation in the code editor starts in Normal mode. + +### Customizing Keybindings + +At the moment, Warp only supports default Vim keybindings. + +One exception is the keyboard shortcut for exiting insert mode, which can be rebound under**Settings** > **Keyboard shortcuts** > **Exit Vim Insert Mode**, or through the [Command Palette](/terminal/command-palette/) search for "Exit Vim Insert Mode". + +## Supported Keybindings + +Below is a list of the vim functionality implemented in Warp so far. + +### Movement + +See [Vim docs: motion](https://vimdoc.sourceforge.net/htmldoc/motion.html) for more information. + +#### Basic + +| Command(s) | Description | +| ---------------------------- | --------------------------------------------------- | +| `h`, `j`, `k`, `l` | single-char movement | +| `<space>`, `<backspace>` | single-char movement with line wrap | +| `w`, `W`, `b`, `B`, `e`, `E` | word movement | +| `ge`, `gE` | end of previous word | +| `$` | end of line | +| `0` | beginning of line | +| `^` | first non-whitespace character of line | +| `%` | jump to matching bracket | +| `[`, `]` | prev/next unmatched bracket | +| `_` | beginning of the current line | +| `+` | first non-whitespace character of the next line | +| `-` | first non-whitespace character of the previous line | +| `{`, `}` | prev/next paragraph | + +#### Multi-line-related + +| Command(s) | Description | +| ---------- | ----------------------- | +| `gg`, `G` | jump to first/last line | + +### Editing + +| Command(s) | Description | +| ---------- | ----------------------------------------------------------- | +| `r` | replace character under cursor | +| `d`, `D` | delete a range or object | +| `c`, `C` | change a range or object (delete, then go to insert mode) | +| `s`, `S` | substitute (like change, but can only delete at the cursor) | +| `x`, `X` | delete under cursor | +| `y`, `Y` | yank (copy) into the clipboard | +| `p`, `P` | paste from the clipboard | +| `u`, `⌃r` | undo, redo | +| `~` | toggle upper/lowercase under cursor | +| `gu` | lowercase under cursor (`u` in visual mode) | +| `gU` | uppercase under cursor (`U` in visual mode) | +| `J` | join current and following lines | +| `.` | repeat last edit | +| `gcc` | toggle comments on current line | +| `gc` | toggle comments on visual selection | + +See [Vim docs: editing](https://vimdoc.sourceforge.net/htmldoc/editing.html) for more information. + +#### Text Objects + +| Command(s) | Description | +| ---------------- | ------------------------------------------ | +| `i` | inner (exclude delimiters in text object) | +| `a` | around (include delimiters in text object) | +| `w`, `W` | whitespace-delimited string (word) | +| `"`, `'`, \`\`\` | quote-delimited string | +| `(`, `{`, `[` | parenthesized/bracketed string | + +See [Vim docs: text objects](https://vimdoc.sourceforge.net/htmldoc/motion.html#text-objects) for more information. + +### Search + +#### Character Search + +| Command(s) | Description | +| ------------------ | ------------------------------------------------------ | +| `t`, `T`, `f`, `F` | find next/prev matching character on line | +| `;` | repeat last character search in the same direction | +| `,` | repeat last character search in the opposite direction | + +See [Vim docs: left-right motions](https://vimdoc.sourceforge.net/htmldoc/motion.html#f) for more information. + +#### General Search + +Unlike Vim, general search commands don't search within the buffer. Instead, they open Warp's native command search. + +| Command(s) | Description | +| ------------------ | ------------------------ | +| `/`, `?`, `*`, `#` | open Warp command search | + +### Mode Switching + +| Command(s) | Description | +| ---------- | ----------------------------------------------------------------- | +| `i` | insert text before the cursor | +| `I` | insert text before the first non-whitespace character in the line | +| `a` | append text after the cursor | +| `A` | append text at the end of the line | +| `o` | begin new line below the cursor and insert text | +| `O` | begin new line above the cursor and insert text | +| `v` | visual character mode | +| `V` | visual line mode | + +See [Vim docs: insert](https://vimdoc.sourceforge.net/htmldoc/insert.html#insert) and [Vim docs: visual mode](https://vimdoc.sourceforge.net/htmldoc/visual.html#visual-mode) for more information. + +### Registers + +| Command(s) | Description | +| ---------- | --------------- | +| `"` | register prefix | + +Warp currently supports the following registers: + +| Register name | Description | +| ---------------- | ---------------------------------------------------------------- | +| `a`–`z`, `A`–`Z` | named registers | +| `+` | system clipboard | +| `*` | system clipboard | +| `"` | unnamed register, containing the text of the last delete or yank | + +See [Vim docs: registers](https://vimdoc.sourceforge.net/htmldoc/change.html#registers) for more information. + +## Feedback + +The best way to report bugs and request features is through Warp's [GitHub Issues](https://github.com/warpdotdev/Warp/issues) page. Please note that the issue or request is for Vim Keybindings. diff --git a/src/content/docs/code/code-editor/file-tree.mdx b/src/content/docs/code/code-editor/file-tree.mdx new file mode 100644 index 0000000..263d4d1 --- /dev/null +++ b/src/content/docs/code/code-editor/file-tree.mdx @@ -0,0 +1,49 @@ +--- +title: File Tree (Project Explorer) +description: >- + Browse, open, and manage project files with Warp's native file tree and + context menu actions. +--- + +![Warp's native file tree showing the project's file and folder structure in the left panel.](../../../../assets/terminal/filetree-main.png) + +Warp includes a **native file tree** that makes it easy to explore and manage project files. The file tree is available whenever in any directory and it automatically reflects your project structure as files are added, removed, or changed. + +### Opening the file tree + +You can open the file tree from the tools panel on the left hand side: + +* **Tools panel**: Click the Tools sidebar button, then open the File Tree tab (first tab in the panel). +* Press `CMD + \` to open the left panel, then assign your own shortcut for File Tree (and Warp Drive) in **Settings** > **Keyboard shortcuts**. + +![Opening the File Tree from the Tools panel sidebar in Warp.](../../../../assets/terminal/file-tree-project-explorer-tools-panel.png) + +:::note +Warp supports icons for common file types. If a file type is missing an icon, please [file a GitHub issue](https://github.com/warpdotdev/Warp/issues) so we can review and add support. +::: + +### Browsing and opening files + +Clicking on a file opens it directly in Warp’s [**native Code Editor**](/code/code-editor/), where you can view and edit code in a separate pane or tab. + +## File and folder actions + +Right-clicking any **file** opens a context menu with several useful options: + +* **Open in new pane**: Open the file in a side-by-side pane. +* **Open in new tab**: Open the file in a new tab. +* **Attach as context**: Insert the file into an agent prompt so the Agent can analyze or reference it. +* **Copy path**: Copy the absolute file path. +* **Copy relative path**: Copy the path relative to your current working directory. + +![Right-click context menu on a folder in the file tree.](../../../../assets/terminal/file-tree-context-menu.png) + +Right-clicking any **folder** opens a context menu with the following options: + +* **Create new file**: Add a new file directly from the tree. + + ![Creating a new file directly from a folder's right-click context menu in the file tree.](../../../../assets/terminal/file-tree-new-file.png) +* **Attach as context**: Insert the selected file into your agent prompt so the Agent can analyze or reference it. +* **Copy path**: Copy the absolute file path to your clipboard. +* **Copy relative path**: Copy the path relative to your current working directory. + diff --git a/src/content/docs/code/code-editor/find-and-replace.mdx b/src/content/docs/code/code-editor/find-and-replace.mdx new file mode 100644 index 0000000..7d793a0 --- /dev/null +++ b/src/content/docs/code/code-editor/find-and-replace.mdx @@ -0,0 +1,35 @@ +--- +title: Find and Replace +description: >- + Search and replace text in Warp's code editor with regex, case sensitivity, + and smart case preservation. +--- +import DemoVideo from '@components/DemoVideo.astro'; + +## Find + +Press `CMD-F` on macOS or `CTRL-SHIFT-F` on Windows and Linux to open the find menu. As you type, all matches in the file are highlighted, and the match closest to your cursor is selected. + +* Press `ENTER` or use the down arrow to jump to the next match +* Press `SHIFT-ENTER` or use the up arrow to go to the previous match +* Click "Select All" to highlight all matches and close the menu + +You can toggle regex and case-sensitive search options directly in the query editor. + +<DemoVideo src="/assets/terminal/code-find-menu.mp4" label="using find in the code editor" /> + +## Replace + +Click the dropdown to the left of the find menu to open the replace options. + +* Press Enter to replace the currently selected match +* Use Replace All to replace all matches + +Toggle Preserve Case to keep the original casing of replaced text. Case is preserved in text that contains PascalCase, camelCase, hyphens, and underscores. For example: + +* Replacing “old” with “new” will turn “Old” into “New” and “OLD” into “NEW” +* Replacing “oldValue” with “NewValue” will result in “newValue” +* Replacing “OldValue” with “newValue” will result in “NewValue” +* Replacing “my-Old-VALUE” with “my-new-value” will result in “my-New-VALUE” + +<DemoVideo src="/assets/terminal/code-replace-menu.mp4" label="using replace in the code editor" /> diff --git a/src/content/docs/code/code-editor/index.mdx b/src/content/docs/code/code-editor/index.mdx new file mode 100644 index 0000000..2ff17d6 --- /dev/null +++ b/src/content/docs/code/code-editor/index.mdx @@ -0,0 +1,71 @@ +--- +title: Built-in Code Editor +description: >- + Make in-context code edits with Warp's built-in editor, featuring syntax + highlighting, tabs, and Vim keybindings. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Warp comes with a native code editor designed for quick, in-flow edits alongside your Agent conversations. Instead of switching back and forth to an IDE, you can open and edit files directly in Warp — with essentials like syntax highlighting, a tabbed file viewer, find and replace, Vim keybindings, and a file tree for browsing and adding files as context. + +The editor is built for fast changes to agent-generated code: renaming a variable, tweaking copy, or rewriting a short function. Having just enough editing power in-context makes it easier to land an agent’s changes and keep momentum. + +### Opening files in Warp + +**You can open files in the editor in several ways:** + +1. **Click a file path** from the terminal output or an AI conversation and select "Open in Warp." +2. **Use the file menu in the Command Palette** (`CMD + O` on macOS, `CTRL + SHIFT + O` on Windows or Linux) when in a Git-tracked repo to search for and open files inside that repo. + + 1. You can also access this via the magnifying glass icon in the pane coding toolbelt at the top left of any pane. + + ![Magnifying glass icon in the pane coding toolbelt for opening the file search.](../../../../assets/terminal/search-files-icon.png) +3. **Browse via the** [File Tree (Project Explorer)](/code/code-editor/file-tree/) to open or create files. +4. **Opening a generated code diff** from an Agent Conversation: [Code Diffs in Agent Conversations](/agent-platform/local-agents/code-diffs/). + +<VideoEmbed url="https://screen.studio/share/H7hTUgf2" /> + +**To save your changes to files**: use `CMD + S` on macOS or `CTRL + S` on Windows or Linux. + +### Tabbed file viewer + +Warp can group multiple files into a single tabbed viewer, reducing clutter and making it easier to work across multiple files. + +![Multiple files grouped into a single tabbed file viewer in Warp's code editor.](../../../../assets/terminal/tabbed-file-viewer.png) + +* Enabled by default for new users (can be toggled in **Settings** > **Features** > **General** > **Group files into a single editor pane**) +* Reorder, close, or drag file viewers between tabs. +* Merge entire panes together by dragging one into another. + +**Here's a more in-depth demo:** + +<VideoEmbed url="https://www.loom.com/share/a682461da66944f583e2fa3d27b71189?sid=679ce8f6-e530-4c0d-99ab-0613d1269f8b" /> + +### **File layout options** + +Choose how new files open in Warp by default in: **Settings** > **Features** > **General** > **Choose a layout to open files in Warp** + +* **Split pane**: new files open alongside the current editor +* **New tab**: new files open in their own tabbed viewer + +### Supported languages + +The editor supports syntax highlighting and editing for a wide range of languages, including: + +Rust, Go, YAML, Python, JavaScript/TypeScript, JSX/TSX, Java/Groovy, C++, Shell/Bash, C#, HTML, CSS, C, JSON, HCL/Terraform, Lua, Ruby, PHP, TOML, Swift, Kotlin, Starlark, SQL, Powershell, and Elixir. + +We’re continuously expanding language support. + +### Shared buffers + +When you open the same file in multiple tabs or panes, Warp keeps them in sync automatically. Edits made in one view are immediately reflected in all others, and when a file changes on disk (for example, after switching branches), every view updates together. + +### Other editor features + +Warp's native code editor also supports the following features: + +* [Language Server Protocol (LSP)](/code/code-editor/language-server-protocol/) - Get hover info, go-to-definition, find references, inline diagnostics, and format-on-save powered by language servers for Rust, Go, Python, TypeScript/JavaScript, and C/C++. +* [File Tree (Project Explorer)](/code/code-editor/file-tree/) - Browse, open, and manage your project with Warp's native file tree. +* [Find and Replace](/code/code-editor/find-and-replace/) - Use Warp's built-in find and replace to quickly search across a file, jump between matches, and make precise edits with options for regex, case sensitivity, and smart case preservation. +* [Code Editor Vim Keybindings](/code/code-editor/code-editor-vim-keybindings/) - Use Vim keybindings to edit code and text in Warp's native code editor. + diff --git a/src/content/docs/code/code-editor/language-server-protocol.mdx b/src/content/docs/code/code-editor/language-server-protocol.mdx new file mode 100644 index 0000000..952f38b --- /dev/null +++ b/src/content/docs/code/code-editor/language-server-protocol.mdx @@ -0,0 +1,88 @@ +--- +title: Language Server Protocol (LSP) +description: >- + Get hover info, go-to-definition, diagnostics, and format-on-save via + built-in LSP support. +--- + +Warp's code editor includes built-in support for the [Language Server Protocol](https://microsoft.github.io/language-server-protocol/), giving you IDE-grade code intelligence directly in the terminal. When you enable an LSP server for your project, you get hover documentation, go-to-definition, find references, inline diagnostics, and automatic formatting — all without leaving Warp. + +## Supported languages + +Warp ships with support for the following language servers: + +| Language | Server | File extensions | +| --- | --- | --- | +| Rust | `rust-analyzer` | `.rs` | +| Go | `gopls` | `.go` | +| Python | `pyright` | `.py` | +| TypeScript / JavaScript | `typescript-language-server` | `.ts`, `.tsx`, `.js`, `.jsx`, `.mjs`, `.cjs` | +| C / C++ | `clangd` | `.c`, `.C`, `.h`, `.H`, `.hh`, `.cc`, `.cpp`, `.cxx`, `.hpp`, `.hxx` | + +We're actively expanding language support. To request a language, [file a GitHub issue](https://github.com/warpdotdev/Warp/issues). + +## How it works + +When you `cd` into a workspace with enabled language servers, Warp automatically starts them in the background. Features like hover, diagnostics, and go-to-definition become available once a server finishes initializing. As you edit, Warp sends incremental updates to keep everything in sync. If you close all files and terminals for a workspace, Warp shuts down the idle server to free resources. + +:::note +Warp uses your shell's `PATH` to locate language server binaries. If a server isn't found on your `PATH`, Warp can install it for you (see [Enabling a server](#enabling-a-server) below). +::: + +## Enabling and managing language servers + +### Enabling a server + +Language servers are enabled **per workspace** (per Git repository root). When you open a file in a supported language for the first time, the **editor footer** shows an option to enable the appropriate language server. If the server binary is not installed on your system, Warp offers to install it for you. + +You can also manage servers from **Settings** > **Code** > **Indexing and projects**, where each initialized workspace shows its enabled language servers and their status. + +### Server status indicator + +The code editor footer displays a status icon for the active language server: + +* 🟢 **Green** - Server is running and ready. +* 🟡 **Yellow** - Server is starting or processing a background task. +* 🔴 **Red** - Server failed to start. Click the icon to see options. +* ⚪ **Gray** - Server is stopped. + +Clicking the status icon opens a menu with options to **restart**, **stop**, **start**, or **view logs** for the server. + +### Server logs + +Each language server writes logs to a file on disk. Access these logs from the footer menu (click the status icon and select "Open Logs") or from **Settings** > **Code** > **Indexing and projects**. Logs are useful for debugging server startup failures or unexpected behavior. + +## Editor features powered by LSP + +### Hover information + +Hover over a symbol to see its type signature, documentation, and other details provided by the language server. The hover tooltip appears after a brief delay and supports rich content including code blocks and Markdown. + +### Go to definition + +Hold `CMD` (macOS) or `CTRL` (Windows/Linux) and click a symbol to jump to its definition. If the definition is in a different file, Warp opens it in the code editor. While you hold the modifier key, the symbol is underlined on hover to indicate it is navigable. + +### Find references + +`CMD`-click (macOS) or `CTRL`-click (Windows/Linux) on a symbol that is already at its definition to see a **Find References** card listing all references across the workspace. Click any reference to navigate to it. + +### Inline diagnostics + +Warp displays errors and warnings from the language server as dashed underlines directly in the editor. Hover over an underlined range to see the full diagnostic message. Diagnostics update in real time as you edit and are briefly cleared while the server recalculates. + +### Format on save + +When you save a file (`CMD + S` / `CTRL + S`), Warp requests formatting from the language server before writing to disk. This applies the server's configured formatting rules (indentation, trailing whitespace, final newlines, etc.). If the server doesn't support formatting, the file is saved without formatting changes. + +### Right-click context menu + +When an LSP server is connected, right-clicking in the editor opens a context menu with LSP-powered actions, including go-to-definition and find references. + +LSP features stay in sync across [shared buffers](/code/code-editor/#shared-buffers) — if the same file is open in multiple tabs or panes, diagnostics, hover, and other features reflect the same content regardless of which view you're looking at. + +## Limitations + +* **Local sessions only** - LSP is not available over SSH or WSL sessions. These are tracked in GitHub issues [#6831](https://github.com/warpdotdev/Warp/issues/6831) (SSH) and [#6744](https://github.com/warpdotdev/Warp/issues/6744) (WSL). +* **One server per language** - Each language maps to a single server (for example, Rust always uses `rust-analyzer`). Custom server configurations are not yet supported. +* **Project-scoped** - Language servers operate at the Git repository root level. Files outside a repository may not receive LSP features. +* **Server availability** - Some features (like formatting) depend on the specific language server's capabilities. Not all servers support all features. diff --git a/src/content/docs/code/code-review.mdx b/src/content/docs/code/code-review.mdx new file mode 100644 index 0000000..4f4a6bb --- /dev/null +++ b/src/content/docs/code/code-review.mdx @@ -0,0 +1,148 @@ +--- +title: Code Review panel +description: >- + The Code Review panel lets you review, edit, and manage Git diffs in real + time, with options to attach, revert, or open files directly. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +## Overview + +When you are working locally in a Git repository with uncommitted changes, the **Code Review panel** lets you inspect, edit, and manage code changes directly inside Warp. It integrates with Git and Warp's Agents, giving you the ability to: + +* Review diffs and attach them as context for the Agent +* Apply, edit, or revert changes in real time +* See changes made outside of Warp or by Warp's Agents automatically reflected + +Any uncommitted changes appear in the panel (or compare the changes on your branch against `main` or `master` ). Switching branches or saving files updates the panel instantly, so it always reflects the current state of your codebase. + +<VideoEmbed url="https://www.loom.com/share/96581523168742eb9b95c3973924728c?sid=a3ee9164-4274-4468-ac32-38ce6807f9a8" title="Code Review Demo" /> + +![Full view of Code Review panel and terminal pane.](../../../assets/terminal/code-review-panel-update.png) + +:::note +To review agent-generated diffs, leave inline comments, batch your feedback, and have the agent apply all requested changes, see [Interactive Code Review](/agent-platform/local-agents/interactive-code-review/). +::: + +## Opening the Code Review panel + +The Code Review panel can be opened in several ways. Each entry point makes it easy to inspect and manage changes without leaving your workflow. + +:::tip +You can also open the Code Review panel with `CMD – SHIFT – +` on macOS or `CTRL – SHIFT – +` on Windows and Linux. +::: + +#### 1. Git diff chip (terminal input) + +In terminal mode, when you're in a Git repository with changes, the Git diff chip shows the number of files modified along with lines added and removed. Clicking the chip opens the Code Review panel with the relevant diffs. + +![Terminal input bar showing the Git diff chip with branch name, modified file count, and lines added and removed](../../../assets/terminal/whole-UDI-bar.png) + +![Git diff chip with a View changes tooltip showing branch name, file count, and lines changed](../../../assets/terminal/git-chip-tooltip-1.png) + +#### 2. Agent conversation: review changes button + +When an Agent makes code edits in an [Agent Conversation](/agent-platform/local-agents/interacting-with-agents/), a `Review changes` button appears at the bottom of the conversation. Click the button to open the code review panel. + +![Review changes at bottom of Agent Conversation.](../../../assets/terminal/Blocklist-with-review-changes.png) + +![Agent conversation footer with feedback buttons and a Review changes button](../../../assets/terminal/review-changes-in-footer.png) + +#### 3. Agent conversation: toolbelt (bottom right) + +During an Agent conversation, you can view all changed files in the toolbelt chips at the persistent bottom right. From there, you can open the Code Review panel directly. + +![Agent conversation with toolbelt chips in the bottom right showing file changes and action buttons](../../../assets/terminal/ai_control_panel_buttons_larger_view.png) + +#### 4. Warp tab bar + +In any Git-tracked repository, you can open the Code Review panel by clicking the `Code review` button in the top-right corner of Warp, next to your avatar. + +#### Viewing all edited files + +Inside the Code Review panel, you can open the file sidebar to browse all changed files in your repository. Clicking on a file will automatically scroll to that file in the panel. + +![Viewing all edited files in the code review panel, with the file sidebar open.](../../../assets/terminal/whole-git-diff-view-with-one-file-collapsed.png) + +:::note +By default, the Code Review panel opens as a pane on the right, but you can drag it to reposition wherever you prefer. +::: + +## Reviewing diffs + +By default, the Code Review panel shows all **uncommitted changes** on your current branch, excluding changes to files ignored by `.gitignore`. + +Warp offers two ways to review changes: + +1. **Uncommitted changes**: view all edits you've made locally on the current branch. +2. **Changes vs. main**: compare your branch against `main` or `master` to see what would be included in a pull request to that branch, for instance. + 1. Warp automatically detects the target branch and updates the comparison accordingly. +3. **Changes vs. another branch**: compare your work against any arbitrary branch for stacked PRs, feature comparisons, or alternate base branches. + +You can manually switch between the two views either in the Code Review panel or via the Git diff chip in the terminal input: + +![Changing diff view in the Code Review Panel.](../../../assets/terminal/diff-dropdown-to-change-base-from-the-code-review-pane.png) + +![Changing diff view from the terminal input.](../../../assets/terminal/git-diff-change-base-dropdown.png) + +<div data-full-width="false">![Changing diff view against an arbitrary branch.](../../../assets/terminal/arbitrary-branch-diff.png)</div> + +Any saved edits made outside of Warp (e.g. in another editor), as well as changes applied by Warp's Agents, appear automatically. The panel updates in real time, ensuring it always reflects the current state of your working file and directory. + +#### Attaching diffs as context + +The Code Review pane makes it simple to share changes with the Agent. You can attach an entire diff to a prompt so the Agent has full visibility into what was added or removed. + +![Attaching a diff as context from the Code Review panel.](../../../assets/terminal/attach-diff-hunk-as-context.png) + +This ensures responses are grounded in your latest edits, whether you're asking for feedback, explanations, or follow-up changes. For more details, see [Selection as Context](/agent-platform/local-agents/agent-context/selection-as-context/). + +#### Reverting diffs + +The Code Review panel lets you easily undo changes at different levels. In the gutter next to each diff, you’ll see an option to revert a hunk: roll back a specific set of changes (a “diff hunk”) within a file. This removes the added or modified lines and restores the previous version. + +![Code diff gutter showing the Revert diff hunk tooltip on a changed line](../../../assets/terminal/revert-diff-hunk.png) + +When you revert, the changes are immediately updated in your working directory. The file is restored to match the selected version, so you can continue editing or commit without the reverted code. + +### Opening Files from Code Review + +In addition to reviewing and editing diffs directly in the Code Review pane, you can open a file directly in Warp's [Code Editor](/code/code-editor/). + +![Code Review panel header showing file name, lines changed, and buttons for attach, revert, and open in editor](../../../assets/terminal/code-review-header.png) + +* Clicking the **expand button** (right-most button on the header) opens the file in a new editor tab, allowing you to see the full file beyond just the changed lines. + * This is useful when you need additional context around a diff, want to make broader edits, or prefer working in the full editor rather than inline. +* Once opened, the file behaves like any other editor tab: you can scroll, edit, search, and save. +* Any changes made in the editor automatically sync back into the Code Review pane, so the diff view always stays current. + +**Note**: from this code review file header, you can also attach a file diff as context into Warp's agent, or discard all the changes on a single file. + +#### Directly editing code diffs + +Alternatively, from the Code Review panel, you are able to click and edit the diffs directly: + +![Directly editing code in the Code Review panel inline diff view](/assets/terminal/directly-editing-diffs.gif) + +### Sending comments to a running agent + +You can leave inline comments in the Code Review panel and send them directly to a running coding agent session, including third-party CLI agents like Claude Code, Codex, and others. + +This extends Warp's [Interactive Code Review](/agent-platform/local-agents/interactive-code-review/) workflow to any supported CLI agent running in Warp. The agent receives your batch of comments and applies the requested changes. + +<DemoVideo src="/assets/terminal/code-review-inline-comment.mp4" label="Adding an inline comment on a diff line and sending it to a running agent" /> + +For more on supported agents, see [Third-Party CLI Agents](/agent-platform/cli-agents/overview/). + +### Discarding all changes + +The Code Review panel also lets you discard every uncommitted change on your branch in one action. Clicking Discard all removes all local modifications shown in the panel and restores each file to its state on the base branch. This is useful when you want to reset your working directory, abandon a set of edits, or start a new iteration from a clean slate. + +![Code Review panel header with Uncommitted changes dropdown, attach button, and Discard all button](../../../assets/terminal/discard-all-changes.png) + +Discarding changes will ask you confirm, but still make sure you've saved or backed up anything you want to keep before using it. + +:::note +Warp natively supports Git worktrees for Code Review and other features. See [Git worktrees](/code/git-worktrees/) for details. +::: diff --git a/src/content/docs/code/git-worktrees.mdx b/src/content/docs/code/git-worktrees.mdx new file mode 100644 index 0000000..60b3645 --- /dev/null +++ b/src/content/docs/code/git-worktrees.mdx @@ -0,0 +1,50 @@ +--- +title: Git worktrees +description: >- + Warp natively supports Git worktrees, letting you work on multiple branches + simultaneously with full Code Review, Codebase Context, and Agent support. +--- + +Warp natively supports [Git worktrees](https://git-scm.com/docs/git-worktree) — a Git feature that lets you check out multiple branches simultaneously in separate directories, all backed by the same repository. This is different from simply switching branches: with worktrees, you can have `~/project` on `main` and `~/project-wt/feature-x` on `feature-x` at the same time, with no stashing or context-switching required. + +## How worktrees work in Warp + +Warp automatically detects worktree checkouts. When you open a terminal in a worktree directory, Warp recognizes the `.git` file that points back to the main repository and treats the worktree as a fully functional repository: + +* **Code Review panel** — Each worktree has its own Code Review panel showing uncommitted changes for that worktree's branch. You can review diffs, revert hunks, and discard changes independently in each worktree. +* **Git Status chip** — The Git diff chip and branch indicator in the input bar reflect the correct branch and change counts for whichever worktree your terminal is in. +* **File watching** — Warp watches both the worktree's working directory and the shared `.git` directory. Changes to shared Git state (such as new commits pushed to the remote) are detected and propagated across all open worktrees. +* **Codebase Context** — Each worktree is indexed independently for [Codebase Context](/agent-platform/capabilities/codebase-context/), so Agents have accurate context for whichever worktree you're working in. +* **Repository-scoped features** — Project rules (`AGENTS.md`, `WARP.md`), ignore files, and other repository-scoped settings work correctly within each worktree. + +## When to use worktrees + +Worktrees are especially useful when: + +* **Reviewing a PR while working on your own branch** — Open the PR branch in a separate worktree without disrupting your in-progress work. +* **Running tests on one branch while coding on another** — Keep a long test suite running in one worktree while continuing development in another. +* **Parallel local agent work** — When orchestrating multiple local agents on the same repository, each agent can operate in its own worktree to avoid file conflicts. + +## Creating a worktree + +To create a new worktree from your terminal: + +```bash +# Create a worktree for an existing branch +git worktree add ../my-feature feature-branch + +# Create a worktree with a new branch +git worktree add -b new-branch ../new-branch main + +# List all worktrees +git worktree list + +# Remove a worktree when done +git worktree remove ../my-feature +``` + +Once created, open the worktree directory in a new Warp tab or pane. Warp detects it automatically — no additional configuration is needed. + +:::note +Commit state change notifications (e.g. detecting new commits) may be slightly delayed in worktrees compared to standard repositories. Warp is actively improving this. +::: diff --git a/src/content/docs/code/overview.mdx b/src/content/docs/code/overview.mdx new file mode 100644 index 0000000..3b93faf --- /dev/null +++ b/src/content/docs/code/overview.mdx @@ -0,0 +1,94 @@ +--- +title: Code overview +description: >- + Generate and edit code with Warp's coding agent, review inline diffs, and + apply changes across your codebase. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +:::note +Several coding features — including Codebase Context, code diffs, the code editor, and the file tree — are not yet available in SSH or WSL sessions. +::: + +## From prompt to production + +Warp Code is a suite of features designed to help you take agent-generated code from the initial prompt and project setup all the way to deployment and production. It is powered by Warp’s dedicated coding agent, which consistently ranks among the top results on [SWE-bench Verified](https://www.swebench.com/#verified) and [Terminal-Bench](https://www.tbench.ai/leaderboard). + +In addition to Warp’s modern, [native code editor](/code/code-editor/), it includes: + +* [Codebase Context](/agent-platform/capabilities/codebase-context/) for accurate, context-aware agent responses +* [Project Rules](/agent-platform/capabilities/rules/) and Commands to tailor agent behavior per repository +* A dedicated [Code Review](/code/code-review/) experience for reviewing and editing diffs +* [Zero-state and setup flows](/code/overview/#getting-started-with-coding-in-warp) to quickly start a new project or initialize an existing one + +### Coding Agent + +Warp’s coding agent is designed to help you generate, edit, and manage code directly in the [Agentic Development Environment](https://www.warp.dev/blog/reimagining-coding-agentic-development-environment). It detects opportunities to apply code diffs and surfaces them inline, allowing you to review and apply changes without switching to an external IDE. When you need to make manual edits, you can open Warp’s native code editor. + +### How it works + +* **Prompt-driven coding**: You write natural language prompts such as _“Add a retry mechanism to this API call”_ or _“Fix the failing unit test in auth.test.ts.”_ +* **Inline code diffs**: When the agent proposes changes, it shows them as diffs you can inspect, modify, or reject. +* **Agent steering**: You can refine prompts, interrupt and retry, or attach context (such as a file, diff, or selection) to guide the agent toward better results. + +<VideoEmbed url="https://youtu.be/W8rCsznM5HA" title="Coding Features Overview" /> + +:::note +Warp's coding agent only works on local repositories. The agent can make changes on remote or docker repositories, but falls back to using terminal commands (i.e. `sed`, `grep` ) to make the changes. +::: + +### Examples of coding capabilities + +Code responds to prompts related to code generation, editing, and analysis. Here are some examples: + +* **Code creation** + * “Write a function in JavaScript to debounce an input” + * “Generate a Python class for managing user sessions with Redis.” +* **Error-driven fixes** + * “Fix the TypeScript error shown in the last build output.” + * “Resolve this merge conflict by keeping backend changes and updating tests accordingly.” +* **Refactoring** + * “Update all instances of var to let in this file.” + * “Extract the database logic from app.js into a new db.js module and update imports.” +* **Multi-file and repo-wide changes** + * “Add headers to all .py files in this directory.” + * “Replace requests with httpx across the codebase, updating imports and error handling.” +* **Complex workflows** (examples shown below — in practice, prompts should include more detail for best results) + * “Implement OAuth2 authentication, update affected routes, and add tests.” + * “Identify functions without test coverage and create Jest test files for them.” + * “Optimize slow SQL queries in queries.sql and regenerate migrations.” + +<VideoEmbed url="https://youtu.be/IuFSuOYstfg" title="How to kick off a coding task" /> + +<VideoEmbed url="https://youtu.be/dm-P63USsVg" title="How to interpret & edit Warp’s coding output" /> + +## Getting started with coding in Warp + +Warp provides multiple entry points to begin coding with agents, whether you are starting a new project, opening an existing one, or cloning from GitHub. Each new tab shows a **zero state** that lets you choose how to proceed. + +![Zero-state tab with 3 starting points for agentic coding in Warp.](../../../assets/terminal/code_mode.png) + +#### 1. Starting a new project + +To begin a new project, select **Create a New Project** from the tab. You can start directly with a prompt (Warp will suggest ideas) or configure the project manually. Warp sets up the repository with an `AGENTS.md` file (filename must be in all caps) containing [project rules](/agent-platform/capabilities/rules/#project-rules) and enables [codebase indexing](/agent-platform/capabilities/codebase-context/) to provide the agent with full context. + +#### 2. Open an existing repo + +Select **Open Repository** to use your computer's file picker. If you choose a Git repository, Warp automatically changes into the directory and runs the `/init` setup command (a built-in "[slash command](/agent-platform/capabilities/slash-commands/)") if the repo has not already been initialized. Warp will detect the repository, index the codebase, and prepare it for coding. + +* For non-Git folders, Warp simply changes into the directory without initialization. +* If you have an existing project that is not yet initialized, you can run `/init` manually to bootstrap it with a version-controlled `AGENTS.md` file. +* This view also shows a list of your three most recently used repositories and AI conversations for quick access, as well as a list of recent directories (which behave like running `cd`). + +#### 3. Clone a repo + +Select **Clone Repository** to paste in a repo link or clone directly from GitHub. Warp places you in the cloned folder and automatically runs the `/init` flow to set up project rules and indexing. + +## Learn more about code features: + +* [Code Editor](/code/code-editor/) - Warp's built-in code editor lets you make quick, in-context edits with essentials like syntax highlighting, tabs, find and replace, Vim keybindings, and a file tree. + * [Language Server Protocol (LSP)](/code/code-editor/language-server-protocol/) - Warp integrates with language servers to provide hover info, go-to-definition, find references, inline diagnostics, and format-on-save for Rust, Go, Python, TypeScript/JavaScript, and C/C++. +* [Codebase Context](/agent-platform/capabilities/codebase-context/) - Warp indexes your Git-tracked codebase to help Agents understand your code and generate accurate, context-aware responses. No code is stored on Warp servers. +* [Code Review](/code/code-review/) - review, edit, and manage Git diffs in real time, with options to attach, revert, or open files directly. + * You can also enter [Interactive Code Review](/agent-platform/local-agents/interactive-code-review/) to comment on changes, guide the agent, or adjust individual edits as they happen. +* [Code Diffs](/agent-platform/local-agents/code-diffs/) - Learn how to review, refine, and apply code changes generated by Warp's agents using the built-in visual diff editor. diff --git a/src/content/docs/code/ssh-feature-support.mdx b/src/content/docs/code/ssh-feature-support.mdx new file mode 100644 index 0000000..9d704d8 --- /dev/null +++ b/src/content/docs/code/ssh-feature-support.mdx @@ -0,0 +1,38 @@ +--- +title: Feature support over SSH +description: >- + A reference for which Warp coding features are available over SSH and which + are limited to local sessions. +--- + +When you [Warpify an SSH session](/terminal/warpify/ssh/), Warp's core terminal features — the input editor, completions, blocks, history search, and more — work the same as they do locally. However, several coding-specific features are **not yet available** in remote sessions because the Agent cannot directly access the remote filesystem. + +:::note +When a native tool is unavailable, the Agent automatically falls back to terminal commands (e.g. `cat`, `sed`, `grep`) to read and edit files. You can still accomplish most coding tasks over SSH, but the experience may be less seamless than working locally. +::: + +## Features that work over SSH + +The following features are fully available in Warpified remote sessions: + +* **Agent Mode conversations** — You can chat with the Agent, ask questions, and request code changes. The Agent will use terminal commands to interact with the remote filesystem. +* **Running shell commands** — The Agent can execute commands on the remote machine on your behalf. +* **Grep and file glob** — The Agent can search for files and patterns using terminal-based grep and glob tools. +* **MCP tools** — Model Context Protocol integrations remain available. +* **Terminal features** — The input editor, command completions, autosuggestions, command history, blocks, and all other core terminal features work as expected. + +## Features not yet available over SSH + +The following features require local filesystem access and are not yet available in Warpified remote (SSH) sessions: + +* **Codebase Context (indexing and search)** — Warp cannot index or semantically search a remote codebase. The Agent will not have access to your full project context when generating responses. Feature request: [GitHub #6831](https://github.com/warpdotdev/Warp/issues/6831) +* **Native file reading** — The Agent cannot read files through Warp's built-in file reading tool. It falls back to terminal commands like `cat` to read file contents. +* **Code diffs** — The Agent cannot apply code diffs natively. It falls back to terminal commands like `sed` to make file edits. +* **Code editor** — Warp's [native code editor](/code/code-editor/) is not yet available in remote sessions. You cannot open, view, or edit files in Warp's built-in editor over SSH. +* **File tree (Project Explorer)** — The [file tree sidebar](/code/code-editor/file-tree/) is not yet available in remote sessions. +* **Code review panel** — The [Code Review](/code/code-review/) panel for reviewing Git diffs is not yet available for remote repos. +* **Computer use** — The Agent cannot take screenshots or interact with the remote machine's desktop. + +:::note +WSL sessions have the same limitations as SSH. Feature request for WSL support: [GitHub #6744](https://github.com/warpdotdev/Warp/issues/6744) +::: diff --git a/src/content/docs/enterprise/enterprise-features/architecture-and-deployment.mdx b/src/content/docs/enterprise/enterprise-features/architecture-and-deployment.mdx new file mode 100644 index 0000000..43009fa --- /dev/null +++ b/src/content/docs/enterprise/enterprise-features/architecture-and-deployment.mdx @@ -0,0 +1,158 @@ +--- +title: Architecture and deployment +description: >- + Understand Warp's system architecture and choose the right deployment model + for your organization - Warp-hosted, self-hosted, or hybrid. +--- + +Warp's architecture separates the **control plane** (orchestration, observability, and LLM inference) from the **execution plane** (where agents run, code is accessed, and commands execute). This separation gives enterprise teams flexibility to choose where sensitive workloads run while maintaining centralized management and visibility. + +Use this information to evaluate which deployment model fits your organization's security, compliance, and operational requirements. + +## System architecture overview + +Warp's cloud agent infrastructure has four key components: + +1. **Trigger** - What starts an agent run (CI step, webhook, cron schedule, Slack mention, CLI command, or API/SDK call). +2. **Orchestration** - What decides what to run and tracks it (Oz orchestrator or your own system). +3. **Execution** - Where the agent actually runs (Warp-hosted environment, your infrastructure, or your existing CI/orchestrator). +4. **Visibility** - How the team monitors and intervenes (Oz dashboard, session sharing, APIs/SDKs). + +{/* TODO: Insert system architecture diagram once received from design team */} + +### High-level data flow + +* **Warp terminal (client)** ↔ **Warp backend (control plane)** ↔ **LLM providers** +* The Warp backend handles task orchestration, observability, and LLM inference routing. +* LLM providers operate under **Zero Data Retention (ZDR)** agreements. They do not store or train on your data. +* The **execution plane** is where source code is accessed, commands run, and build artifacts are produced. This can run on Warp's infrastructure or yours. + +## Warp-hosted (SaaS) + +Warp-hosted is the default deployment model. Oz agents run on Warp-managed infrastructure with no setup required from your team. + +### How it works + +* Agents execute in **isolated Docker containers** on Warp-hosted infrastructure (GCP). +* The Oz orchestrator manages agent lifecycle - provisioning, execution, monitoring, and cleanup. +* Environments are ephemeral and destroyed after each run. + +### Triggers + +Warp-hosted agents can be triggered by: + +* **First-party integrations** - Slack, Linear, and other connected tools +* **Scheduled agents** - Cron-like automation for recurring work +* **CLI** - `oz agent run-cloud` for on-demand cloud execution +* **API/SDK** - Programmatic triggers from your own systems + +### When to use + +* You want the simplest path to scalable cloud agent execution. +* You need to run many tasks in parallel without building sandboxing infrastructure. +* Your security requirements are met by Warp's SOC 2 Type II certified infrastructure with ZDR. + +## Self-hosted execution + +For organizations that need agent execution and source code to remain within their own network boundary, Warp supports self-hosted execution. + +:::note +Self-hosted execution is available exclusively on Warp's **Enterprise** plan. +::: + +### Split architecture + +Self-hosted deployments use a split architecture: + +* **Execution plane (customer-hosted)** - Source code repositories, build artifacts, shell commands, and runtime secrets stay on your infrastructure. Note that during agent interactions, code context is included in LLM prompts and session transcripts that route through Warp's servers under ZDR agreements (see [What transits Warp's servers](#what-transits-warps-servers)). +* **Control plane (Warp-hosted)** - Task orchestration, observability data, and LLM inference route through Warp's servers under Zero Data Retention (ZDR) agreements. + +### Deployment modes + +**Unmanaged** - Use `oz agent run` to run agents in your existing orchestrator or CI environment. Supports Linux, macOS, and Windows with no Docker dependency. + +* Best for teams that already have CI/CD infrastructure or internal orchestrators. +* You control scheduling, scaling, and environment setup. +* Warp provides cloud connectivity, shared context, visibility, and session sharing. + +**Managed** - Run the `oz-agent-worker` daemon to let the Oz platform orchestrate agents in isolated Docker containers on your infrastructure. + +* The worker process connects to Oz via WebSocket and receives tasks automatically. +* Agents run in isolated Docker containers managed by the worker. +* You get the same orchestration capabilities as Warp-hosted, but execution stays on your infrastructure. + +### Network requirements + +Self-hosted agents require **outbound-only** network access. No inbound network access is required. + +**Egress requirements:** + +* Outbound access to Warp's backend services (for orchestration and observability) +* For managed mode: access to Docker Hub and GitHub (for container images and repository access) + +### When to use + +* Compliance or security requirements prevent using Warp-hosted compute. +* Source code and execution must stay within your network boundary. +* You want Oz orchestration and visibility without sending code to Warp's infrastructure. + +## Hybrid deployments + +Organizations can combine Warp-hosted and self-hosted execution to balance convenience with security requirements. + +### How it works + +* Route sensitive workloads (e.g., production code, regulated data) to self-hosted agents. +* Route less sensitive workloads (e.g., open-source tooling, internal utilities) to Warp-hosted agents. +* Both execution modes share the same Oz dashboard, session sharing, and API/SDK visibility. + +### Example configurations + +* **By sensitivity** - Production repositories run on self-hosted agents; staging and development run on Warp-hosted. +* **By team** - Security-sensitive teams (e.g., infrastructure, payments) use self-hosted; other teams use Warp-hosted. +* **By task type** - Scheduled maintenance tasks run on Warp-hosted; ad-hoc debugging runs self-hosted in dev environments. + +## Data flow and boundaries + +Understanding what data stays where is critical for security and compliance decisions. + +### What stays on customer infrastructure (self-hosted) + +* **Source code** - Repository contents and version history +* **Build artifacts** - Compiled outputs and generated files +* **Shell commands** - Terminal commands and their output +* **Runtime secrets** - Environment variables and credentials +* **Execution logs** - Agent run logs and diagnostics + +### What transits Warp's servers + +* **Task orchestration** - Scheduling, routing, and lifecycle management +* **Observability data** - Run status, duration, and metadata +* **LLM inference** - Prompts and responses (which include code context from agent interactions) routed through Warp to contracted LLM providers under ZDR agreements +* **Session sharing data** - Session transcripts, which include code context from agent interactions, when session sharing is enabled for monitoring and collaboration + +## Choosing a deployment model + +Consider the following when selecting a deployment model: + +**Warp-hosted** is right if: +* You want zero infrastructure management for agent execution. +* Your security team is comfortable with SOC 2 Type II certified, ZDR-covered infrastructure. +* You need maximum parallelization and scalability. + +**Self-hosted** is right if: +* Compliance requirements mandate that code stays within your network. +* You need to integrate with existing CI/CD or infrastructure tooling. +* You want full control over the execution environment. + +**Hybrid** is right if: +* Different teams or repositories have different security requirements. +* You want the convenience of Warp-hosted for most work but need self-hosted for sensitive workloads. + +## Related resources + +* [Deployment Patterns](/agent-platform/cloud-agents/deployment-patterns/) - Detailed patterns for CLI-only, Oz-hosted, and self-hosted setups +* [Security overview](/enterprise/security-and-compliance/security-overview/) - Data handling, encryption, and compliance details +* [Bring Your Own LLM](/enterprise/enterprise-features/bring-your-own-llm/) - Route inference through your own cloud infrastructure +* [Admin Panel](/enterprise/team-management/admin-panel/) - Configure agent policies and security settings +* [Contact sales](https://warp.dev/contact-sales) - Discuss deployment options for your organization diff --git a/src/content/docs/enterprise/enterprise-features/bring-your-own-llm.mdx b/src/content/docs/enterprise/enterprise-features/bring-your-own-llm.mdx new file mode 100644 index 0000000..326b731 --- /dev/null +++ b/src/content/docs/enterprise/enterprise-features/bring-your-own-llm.mdx @@ -0,0 +1,228 @@ +--- +title: Bring your own LLM +description: >- + Route Warp's agents through your AWS Bedrock models for billing control and + infrastructure flexibility. +--- + +Warp supports **Bring Your Own LLM (BYOLLM)** for enterprise teams that need to run inference on their own cloud infrastructure. With BYOLLM, your team can use Warp's agents while routing inference through models hosted in your AWS Bedrock environment. + +This gives you control over cloud spend and model hosting, without changing how your team works in Warp. + +:::caution +BYOLLM currently supports **AWS Bedrock** only. Coming soon: Azure Foundry and Google Vertex support. + +BYOLLM applies to interactive Oz agents in the terminal. Oz cloud agents do not yet support BYOLLM routing. +::: + +:::note +BYOLLM is only available on Warp's Enterprise plan. Contact [warp.dev/contact-sales](https://warp.dev/contact-sales) to learn more. +::: + +## Key features + +* **Cloud-native credentials** - Authenticate using each user’s AWS IAM identity. Warp does not store API keys. +* **Admin-enforced routing** - Team admins configure which models are available to users in AWS Bedrock, with the ability to disable non-Bedrock model access entirely. +* **Consolidated billing** - Inference costs are billed directly to your AWS account, leveraging existing cloud commitments. + +## How BYOLLM works + +{/* TODO: Add architecture diagram showing BYOLLM request flow (admin configures routing → user authenticates to AWS → Warp routes request → inference in customer AWS account) */} + +When BYOLLM is enabled, Warp redirects inference calls to your AWS Bedrock environment instead of using model providers' direct APIs. + +Here's the high-level flow: + +1. **Admin configures routing** - Your team admin sets routing policies in Warp's admin settings (e.g., "Route Claude Sonnet 4.5 through AWS Bedrock; disable direct Anthropic API"). +2. **Team members authenticate** - Each team member authenticates to AWS locally using the AWS CLI (`aws login`). +3. **Warp routes requests** - When a team member uses an interactive Oz agent in the terminal, Warp uses their short-lived session credentials to authenticate requests to your configured AWS Bedrock API endpoint. +4. **Inference executes in your cloud** - The model runs in your AWS account. Responses return to the Warp client. + +### Credential lifecycle + +BYOLLM uses **cloud-native IAM authentication**, not long-lived API keys: + +* **Automatic refresh** - Session tokens refresh automatically every ~15 minutes. Users can enable auto-refresh by opening **Settings** and searching for `AWS Bedrock`, or when prompted during first credential expiration. With auto-refresh enabled, sessions can run uninterrupted for up to 12 hours (depending on your AWS admin configuration). +* **Per-user credentials** - Credentials are not shared across the organization. Your cloud provider's default credential provider chain (e.g., AWS CLI) provisions and refreshes them locally. +* **No storage or logging** - Warp never stores or logs your cloud session tokens on its servers. + +This approach ensures access management stays with your cloud provider, giving admins member-by-member control. + +### Model availability + +BYOLLM supports the intersection of models that Warp supports and models available on AWS Bedrock. Currently, only **Claude models** (Anthropic) are available through AWS Bedrock. OpenAI and Google models are not available on Bedrock. + +To determine which models you can use with BYOLLM: + +* [Model Choice](/agent-platform/capabilities/model-choice/) - Full list of Warp-supported models. +* [Supported models in Amazon Bedrock](https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html) - AWS Bedrock model availability. + +A model must appear on both lists to be available through BYOLLM. + +## Enabling BYOLLM + +### Prerequisites + +Before configuring BYOLLM, confirm the following: + +* Your organization has the desired models enabled in AWS Bedrock. +* You have admin access to both Warp's [Admin Panel](/enterprise/team-management/admin-panel/) and your AWS IAM settings. +* Team members have the AWS CLI installed locally. + +### Step 1: Configure routing policies (admin) + +In the [Admin Panel](/enterprise/team-management/admin-panel/), configure which models should route through AWS Bedrock: + +1. From the [Admin Panel](/enterprise/team-management/admin-panel/), navigate to the BYOLLM or model routing settings. +2. Select which models should use your cloud provider (e.g., "Claude Sonnet 4.5 via AWS Bedrock"). +3. Optionally, disable direct API access to enforce provider-only routing. + +### Step 2: Provision IAM roles (cloud admin) + +Grant your team members the necessary permissions in AWS. Use least-privilege IAM policies. + +**Example: AWS Bedrock minimum IAM policy** + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "BedrockModelAccess", + "Effect": "Allow", + "Action": [ + "bedrock:InvokeModel", + "bedrock:InvokeModelWithResponseStream" + ], + "Resource": [ + "arn:aws:bedrock:*::foundation-model/*", + "arn:aws:bedrock:*:*:inference-profile/*", + "arn:aws:bedrock:*:*:application-inference-profile/*" + ] + } + ] +} +``` + +:::note +This policy covers Warp's current usage. Warp uses global inference profiles for models when available. +::: + +### Step 3: Authenticate locally (team member) + +Each team member authenticates to AWS using the AWS CLI: + +```bash +aws login +``` + +Confirm your AWS environment and region are correctly configured before using Warp. + +### Step 4: Validate + +Run a test prompt in Warp using a model configured for BYOLLM routing. Verify: + +* The request completes successfully. +* Logs appear in AWS CloudWatch. + +## BYOLLM usage and billing behavior + +### Billing + +When a request routes through BYOLLM: + +* **Warp does not consume credits** for that request. +* Your cloud provider account receives the inference costs directly. + +### Routing behavior + +Warp's agents automatically select the best model for your task while respecting your admin's routing policies. If you configure a model for BYOLLM, requests for that model route to AWS Bedrock. + +### Failover behavior + +If a BYOLLM request fails (e.g., due to expired credentials, insufficient permissions, or provider quota limits), Warp attempts to fall back to the next available model your admin has enabled. + +For example, if Claude Sonnet 4.5 on Bedrock fails but your admin also enabled it via direct API, Warp falls back to the direct API to avoid disruption. If a fallback uses a direct API model, that request consumes Warp credits. + +If no fallback is available (e.g., the admin disabled all non-Bedrock models), Warp displays a clear error message. + +## Security and data handling + +### Credential security + +* **No long-lived API keys** — BYOLLM uses cloud-native IAM with short-lived session tokens. +* **Per-user authentication** — Each team member authenticates individually; credentials are not shared. +* **No storage or logging** — Warp never stores or logs your cloud session tokens on its servers. + +### Zero Data Retention (ZDR) + +Warp maintains **SOC 2 compliance** and has **Zero Data Retention (ZDR)** agreements with its contracted LLM providers. + +However, when using BYOLLM: + +* **Your** cloud account settings determine data retention policies. +* Warp cannot enforce ZDR for requests routed through your infrastructure. +* If your cloud account does not have ZDR enabled, your provider may retain data according to their terms. + +### Auditability + +* Warp keeps all runs fully steerable and logged within Warp. +* Your cloud account retains provider-side logs (usage, latency, errors). + +## Troubleshooting + +### Common errors + +* **Missing or expired credentials** — Re-authenticate using `aws login`. To avoid interruptions, enable auto-refresh by opening **Settings** and searching for `AWS Bedrock`, or when prompted during credential expiration. +* **Insufficient permissions** — Verify your IAM policy includes the required actions and resources. +* **Region or model mismatch** — Confirm the model is enabled in your AWS region and that your environment is configured for the correct region. +* **Provider quota limits** — Check your AWS Bedrock quota and request increases if needed. + +### Debugging steps + +1. Verify local authentication: run `aws sts get-caller-identity`. +2. Check your effective IAM policy for the required permissions. +3. Confirm the model ID and region match your Warp configuration. +4. Inspect AWS CloudWatch logs for request details and errors. + +## FAQ + +### How is BYOLLM different from BYOK? + +**BYOK (Bring Your Own Key)** lets individual users add their own API keys for direct model provider access (e.g., Anthropic, OpenAI, Google). Warp stores keys locally on the user's device. + +**BYOLLM (Bring Your Own LLM)** routes inference through your organization's cloud infrastructure (AWS Bedrock) using cloud-native IAM. Admins configure it at the admin level and it applies to the entire team. + +| Feature | BYOK | BYOLLM | +| --- | --- | --- | +| Configuration level | User | Admin/Team | +| Authentication | API keys (local) | Cloud IAM (per-user) | +| Billing | Direct to provider | Your cloud account | +| Data locality | Provider infrastructure | Your cloud infrastructure | + +### Does BYOLLM work with Auto? + +Auto model selection is disabled as soon as your admin disables **any** Direct API model, regardless of your AWS Bedrock configuration. + +If all Direct API models remain enabled and BYOLLM is configured, Auto will try to use your enabled AWS Bedrock models first, falling back to Direct API only if that fails (e.g., invalid/missing AWS credentials, Bedrock outage). + +### Where does compute run and who pays? + +Inference runs in **your AWS account**. You pay AWS directly for compute usage. Warp does not consume credits for BYOLLM-routed requests. + +### What data does Warp store? Do you store our cloud credentials? + +Warp **does not store or log** your cloud session tokens. Credentials are used transiently to sign requests and are never persisted on Warp servers. + +Warp stores standard run metadata (timestamps, model used, etc.) but does not retain the content of your prompts or responses when using BYOLLM. + +### Can admins enforce provider-only routing and disable Warp-managed models? + +Yes. Admins can configure routing policies to require specific models to use BYOLLM and disable direct API access to Warp-managed model endpoints. + +## Related resources + +* [Bring Your Own API Key](/support-and-community/plans-and-billing/bring-your-own-api-key/) +* [Model Choice](/agent-platform/capabilities/model-choice/) — Full list of supported models +* [Admin Panel](/enterprise/team-management/admin-panel/) — Configure team settings +* [Contact Sales](https://warp.dev/contact-sales) — Get help with enterprise setup diff --git a/src/content/docs/enterprise/getting-started/faq.mdx b/src/content/docs/enterprise/getting-started/faq.mdx new file mode 100644 index 0000000..fa5bc73 --- /dev/null +++ b/src/content/docs/enterprise/getting-started/faq.mdx @@ -0,0 +1,70 @@ +--- +title: FAQ +description: >- + Answers to common questions about Warp Enterprise, including login issues, + SSO, and getting started. +--- + +## Login and SSO + +### I can't log in with SSO + +**Problem:** Error message when trying to log in via SSO. + +**Solution:** +1. Make sure you're logging in through [app.warp.dev/login](https://app.warp.dev/login), not your SSO provider's portal. +2. Select **Continue with SSO** and enter your work email or domain. +3. If you have an existing Warp account, log in with your original credentials and [link it to SSO first](https://app.warp.dev/link_sso). +4. Complete the linking process. +5. Log out and log back in with **Continue with SSO**. + +### I logged in with another method before and can't use SSO now + +**Problem:** You created a Warp account with email/Google/GitHub, but your organization now requires SSO. + +**Solution:** +1. Go to [app.warp.dev/login](https://app.warp.dev/login). +2. Log in with your original method. +3. Navigate to [app.warp.dev/link_sso](https://app.warp.dev/link_sso). +4. Complete the linking process. +5. Log out and log back in with **Continue with SSO**. + +### Warp won't open from my SSO provider + +**Problem:** Clicking Warp in Okta/Microsoft Entra ID portal shows an error. + +**Solution:** +This is a known limitation. Warp cannot be launched directly from SSO provider portals. Instead: +1. Go to [app.warp.dev/login](https://app.warp.dev/login). +2. Click **Continue with SSO**. +3. Complete authentication. + +## Team and access + +### Team invite links not working + +**Common causes:** +* Invite link expired or was revoked. +* User's email domain doesn't match configured restrictions. + +**Solution:** +1. Generate a new invite link. +2. Verify domain restrictions match the user's email. + +### Users can't see new admin settings + +**Problem:** You changed a setting in the Admin Panel, but users don't see the change. + +**Solution:** +1. Verify the setting is not set to "Respect User Setting." +2. Ask users to restart Warp to force a settings refresh. +3. Confirm users are members of the correct team. +4. Check that users have logged in with SSO (not a personal account). + +## Additional help + +For more troubleshooting, see: +* [Troubleshooting login documentation](/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/) +* Contact your team admin for organization-specific issues. +* Reach out to Warp support via your team's dedicated Slack/Teams channel. +* Join Warp's [Slack community](https://go.warp.dev/join-preview) to connect with other Warp users and engineers. diff --git a/src/content/docs/enterprise/getting-started/getting-started-developers.mdx b/src/content/docs/enterprise/getting-started/getting-started-developers.mdx new file mode 100644 index 0000000..66ba2fe --- /dev/null +++ b/src/content/docs/enterprise/getting-started/getting-started-developers.mdx @@ -0,0 +1,263 @@ +--- +title: Getting started for developers +description: >- + Download Warp, log in to your team, and start using agents, Codebase + Context, and collaborative features to accelerate your development workflow. +--- + +This guide helps developers get up and running with their team in Warp. You'll learn how to download Warp, log in with your organization's SSO, and configure key features like Codebase Context, Warp Drive, and Agent Profiles to accelerate your work across the entire SDLC (all while staying in your terminal). + +When you use agents in Warp, you're using **Oz agents**. Oz is Warp's programmable agent for running and coordinating agents at scale, whether they run locally on your machine or in the cloud. Oz provides the orchestration, tracking, and control plane that makes scaling agent workflows seamless. + +:::note +New to Warp Enterprise? Try the [Enterprise quickstart](/enterprise/getting-started/quickstart/) for a 10-minute walkthrough of SSO login, Warp setup, and running your first Oz agent. +::: + +## Step 1: Download and install Warp + +Warp is available for macOS, Linux, and Windows. + +### Download Warp + +Visit [warp.dev/download](https://warp.dev/download) and select your platform: + +* **macOS** - Download the `.dmg` installer (macOS 10.15 Catalina or later) +* **Linux** - Download the `.deb`, `.rpm`, or use the install script +* **Windows** - Download the `.exe` installer (Windows 10 or later) + +### Install Warp + +**macOS:** +1. Open the downloaded `.dmg` file. +2. Drag Warp to your Applications folder. +3. Launch Warp from Applications or Spotlight. + +**Linux:** +```bash +# Debian/Ubuntu +sudo dpkg -i warp-terminal_*.deb + +# Fedora/RHEL +sudo rpm -i warp-terminal-*.rpm + +# Or use the install script +curl -fsSL https://warp.dev/install.sh | bash +``` + +**Windows:** +1. Run the downloaded `.exe` installer. +2. Follow the installation wizard. +3. Launch Warp from the Start menu. + +## Step 2: Log in to your team + +### Logging in with SSO + +If your organization uses SSO (most enterprise teams do): + +1. Launch Warp. +2. When prompted, log in or create an account. +3. Click **Continue with SSO**. +4. Enter your work email or your organization's domain. +5. Complete authentication with your SSO credentials when redirected to your identity provider. + +:::caution +Do not attempt to launch Warp directly from your SSO provider's app portal (e.g., Okta dashboard). This will result in an error. Always log in through Warp at [app.warp.dev/login](https://app.warp.dev/login). +::: + +### Logging in with an invite link + +If you received an invite link from your team admin: + +1. Click the invite link in your email or message. +2. From the signup page, log in using SSO if it's configured for your team, otherwise use one of the other sign in methods (Google, GitHub, or email). +3. After authentication, you'll automatically join your team. + +### Linking an existing account to SSO + +If you were using Warp before your organization enabled SSO: + +1. Go to [app.warp.dev/login](https://app.warp.dev/login). +2. Log in with your original method (email, Google, or GitHub). +3. Once logged in, navigate to [app.warp.dev/link_sso](https://app.warp.dev/link_sso). +4. Follow the prompts to link your account to SSO. +5. From now on, use **Continue with SSO** to log in. + +## Step 3: Set up key features + +### Codebase Context + +Codebase Context indexes your Git repositories so agents can understand your code and provide accurate, context-aware responses across large, multi-repo systems. + +**Setting up Codebase Context:** + +First, enable codebase indexing in your settings: + +1. Go to **Settings** > **Code** > **Indexing and projects**. +2. Toggle **Enable Codebase Indexing** to turn it on. +3. Optionally, enable **Index new folders by default** to automatically index repositories as you navigate to them. + +:::caution +Codebase Context is a feature your team admin controls. If you don't see these settings or they are disabled, contact your admin to enable this feature for your team. +::: + +**Indexing your repositories:** + +Once codebase indexing is enabled, you can index individual repositories: + +1. Navigate to a Git repository in your terminal. +2. Run the `/init` command. +3. Warp begins indexing your codebase. +4. You'll be prompted to create an `AGENTS.md` file (optional but recommended). + +**What gets indexed:** + +* All Git-tracked files in your repository +* Up to 200,000 files per repository +* Files excluded in `.gitignore` or `.warpindexingignore` are automatically skipped + +**Privacy:** + +During indexing, your code is sent to Warp's servers for processing where embeddings are created and stored. The code itself is not saved—only the embeddings are persisted. This allows agents to understand your codebase structure and context without storing your actual source code. + +:::note +For Oz cloud agents: Code snippets may be stored as part of conversation records when agents create or modify files, since diffs are preserved in the conversation history. +::: + +### Agent Profiles + +{/* Warp also supports third-party CLI agents (Claude Code, Codex, Copilot), so we say "built-in" rather than "every." */} +Agent Profiles let you configure how Warp's built-in Oz agents behave. Profiles give you direct control over model selection, autonomy, tools, and permissions for your agent workflows. + +**Creating an Agent Profile:** + +1. Go to **Settings** > **Agents** > **Profiles**. +2. Click **New Profile**. +3. Configure: + * **Name and description** + * **Model** - Choose which LLM to use + * **Autonomy level** - How much agents can do without asking + * **Tools** - Enable/disable terminal use, code editing, web search + * **Permissions** - What agents can access (repos, files, secrets) +4. Click **Save**. + +**Using profiles:** + +Switch between profiles based on your task: +* **High autonomy** for routine tasks like writing tests or updating docs +* **Low autonomy** for sensitive operations like infrastructure changes +* **Specific models** for cost optimization or task requirements + +### Warp Drive + +Warp Drive is your workspace for saving and sharing Workflows, Notebooks, Prompts, Rules, and Environment Variables. + +**Accessing Warp Drive:** + +1. Click the tools panel icon in the top left of Warp. +2. Click the Warp Drive icon from the top of the tools panel. +3. Two Warp Drive sections display: + * **Team** (top) - Resources shared across your team. + * **Personal** (bottom) - Your individual resources. + +**What you can add to Warp Drive:** + +* **Workflows** - Parameterized commands you use repeatedly (e.g., deploy scripts, environment setup) +* **Notebooks** - Interactive runbooks combining markdown and executable code blocks +* **Prompts** - Saved agent prompts for recurring tasks (e.g., "review this PR", "write unit tests") +* **Plans** - Agent-generated execution plans for complex tasks that agents can then run step-by-step +* **Rules** - Coding standards and conventions agents should follow +* **Environment Variables** - Configuration that can be loaded into your terminal session + +**Creating your first Workflow:** + +1. From Warp Drive, click **+** in your Personal or Team section. +2. Select **Workflow**. +3. Enter a name, description, and command. +4. Add parameters if needed (e.g., `{{branch_name}}`). +5. Click **Save**. + +**Using team resources:** + +Your team admin may have already created shared resources. Explore the Team section of Warp Drive to see what's available—including onboarding notebooks, deployment workflows, and coding standards rules. + +### MCP (Model Context Protocol) + +MCP connects Warp's agents to external tools and services for enhanced context. + +**Configuring MCP servers:** + +1. Go to **Settings** > **Agents** > **MCP servers** or access via Warp Drive. +2. Browse the library of available MCP servers: + * **Linear** - Access issues and project context + * **Sentry** - Pull error tracking and stack trace information + * **Figma** - Reference designs and specifications + * **GitHub** - Access repository and PR context + * And more... +3. Click **+** next to a server to add it. +4. Configure credentials and connection details. +5. Toggle the server on/off as needed. + +Your team may have shared MCP configurations. Check for a share icon next to team-configured servers to use them without manual setup. + +## Step 4: Start using Warp + +### Everyday workflows + +Warp keeps you in your terminal with agent help across the entire SDLC: + +**Environment setup** +* "Set up Node 20, Python 3.12, and Docker Desktop" +* Save setup steps as a Workflow in Warp Drive for future use + +**Understanding codebases** +* "How does authentication flow through this system?" +* "What patterns does this repo use for error handling?" + +**Writing code** +* Use the `/plan` command for complex features +* Review diffs in real-time with the code review panel +* Leave comments on specific lines for the agent to address + +**Debugging** +* Start a debugger (`gdb`, `lldb`) and bring in an agent +* Agents can operate debuggers and REPLs in natural language +* Attach terminal output to agent conversations for analysis + +**Version control** +* "Stage these changes and write a detailed commit message" +* "Create a PR with a description following our template" +* Set up Rules to enforce Git commit conventions + +**Testing** +* "Write unit tests for this function following our existing patterns" +* "Run the test suite and explain what failed" +* Configure Oz cloud agents to run test suites and validate coverage on PRs in the background + +### Learning resources + +* **Warp Guides** - Short video tutorials at [docs.warp.dev/guides](/guides/) + * Getting Started with Warp + * Warp Code features + * Developer workflows + * MCP, Rules, and Prompts +* **Documentation** - Comprehensive guides at [docs.warp.dev](https://docs.warp.dev) + +## Troubleshooting + +For common login, SSO, and access issues, see the [Enterprise FAQ](/enterprise/getting-started/faq/). + +## Next steps + +Now that you're set up: + +* **Explore agent capabilities** - Learn about [agents in Warp](/agent-platform/local-agents/overview/) and [Oz cloud agents](/agent-platform/cloud-agents/overview/) +* **Contribute to team knowledge** - Add useful Workflows, Prompts, and Rules to your team's Warp Drive to compound productivity gains across your team +* **Stay updated** - Check the [Warp changelog](/changelog/) for new features + +## Support and feedback + +* **Send feedback** - Use `Cmd+Shift+F` (macOS) or `Ctrl+Shift+F` (Linux/Windows) or go to **Help** > **Send Feedback** +* **Request features** - Share ideas by [sending us feedback](/support-and-community/troubleshooting-and-support/sending-us-feedback/) +* **Get help** - Enterprise teams have access to priority support via dedicated Slack/Teams channels +* **Join the community** - Connect with other Warp users in our [Slack community](https://go.warp.dev/join-preview) diff --git a/src/content/docs/enterprise/getting-started/getting-started-enterprise.mdx b/src/content/docs/enterprise/getting-started/getting-started-enterprise.mdx new file mode 100644 index 0000000..d02b2a9 --- /dev/null +++ b/src/content/docs/enterprise/getting-started/getting-started-enterprise.mdx @@ -0,0 +1,186 @@ +--- +title: Getting started with Warp Enterprise +description: >- + Set up Warp Enterprise for your organization with SSO configuration, team + management, and admin controls. +--- + +This guide walks your IT or platform admin through initial Warp setup for your organization: configuring SSO, creating your team, inviting users, and setting Admin Panel policies. + +## Prerequisites + +Before you begin: + +* You have an active Warp Enterprise subscription +* You have admin access to your organization's identity provider (Okta, Microsoft Entra ID, Google Workspace, etc.) +* You've identified which team members should have admin privileges in Warp + +## Step 1: Configure Single Sign-On (SSO) + +Warp uses SSO to authenticate users and control access to your organization's Warp team. Warp supports Okta, Microsoft Entra ID, Google Workspace, OneLogin, and any SAML 2.0 or OIDC compatible provider through [WorkOS](https://workos.com). + +SSO setup is coordinated with Warp's team — contact your account team or [enterprise support](https://warp.dev/contact-sales) to get started. For the full setup process and supported providers, see [Single Sign-On (SSO)](/enterprise/security-and-compliance/sso/). + +**Before rolling out to your team**, test SSO login in an incognito window to confirm it works. See [Testing SSO](/enterprise/security-and-compliance/sso/#testing-sso) for steps. + +:::note +After enabling SSO, existing users who signed up with email or OAuth will need to [link their accounts to SSO](https://app.warp.dev/link_sso) before they can continue using Warp with your organization. See [troubleshooting SSO account linking](/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/#i-logged-in-with-another-method-before-and-now-cant-use-sso) for details. +::: + +## Step 2: Create and configure your team + +### Creating your team + +During Enterprise onboarding, Warp's team will work with you to set up your team. This typically happens in one of two ways: + +* **Warp provisions your team** - In most cases, Warp creates the team on your behalf and adds your admin so you can begin configuration right away. +* **You create or bring your own team** - If you already have a Warp team, or prefer to create one yourself, Warp's team will apply the Enterprise plan to it during onboarding. + +In either case, the Enterprise plan must be applied by Warp internally — this cannot be self-served. Your account team will coordinate this with you. To get started, contact your account manager. + +### Team settings + +Some team settings are configured in different places: + +* **Team name** - Configured in **Settings** > **Teams** in the Warp app. Help users identify the right team to join. +* **Domain restrictions** - Limit team invites to specific email domains (e.g., `@yourcompany.com`) +* **Auto-join** - Automatically adds users to your team when they sign in via SSO from your configured domain. The domain must be configured by the Warp team during onboarding — contact your account team to set up or update your team domain. +* **SSO** - Configured through WorkOS, not the Admin Panel. See [Step 1](#step-1-configure-single-sign-on-sso). + +## Step 3: Invite and manage users + +### Inviting users + +There are several ways to add users to your Warp team: + +**Option 1: Invite by email** +1. Navigate to **Settings** > **Teams**. +2. Enter email addresses in the **Invite by Email** field (comma-separated). +3. Click **Invite**. + +**Option 2: Share invite link** +1. Navigate to **Settings** > **Teams**. +2. Copy the team invite link. +3. Share the link via email, Slack, or your preferred communication channel. + +**Option 3: Domain auto-join** + +:::note +Domain configuration is set up by the Warp team during onboarding. Contact your Warp account team to configure or update your team domain. +::: + +1. Once your team domain is configured, users who sign in via SSO from your domain are automatically added to your Warp team. + +### User roles and permissions + +Warp has three user roles: + +* **Team Owner** - Has full access to the Admin Panel and can manage team settings, invite users, assign roles, and transfer ownership of the team. There can only be one Owner. +* **Team Admin** - Same permissions as the Owner, except they can't transfer ownership of the team. +* **Member** - Standard access to Warp features and team resources + +### Managing admins + +To promote or demote team admins: + +1. Navigate to **Settings** > **Teams** > **Team Members**. +2. Find the user you want to modify. +3. Click the **...** (three dots) next to their name. +4. Select **Promote to admin** or **Demote admin**. + +:::note +Teams can have multiple admins. We recommend at least one admin in addition to the Team Owner to prevent access issues if one is unavailable. +::: + +## Step 4: Configure the Admin Panel + +The Admin Panel gives you centralized control over Warp features, permissions, and usage across your team. + +### Accessing the Admin Panel + +1. In Warp, open **Settings**. +2. Navigate to the **Billing and usage** section. +3. Click **Open Admin Panel**. + +Alternatively, visit [app.warp.dev/admin](https://app.warp.dev/admin) directly. + +### Key Admin Panel sections + +* **Billing** - View your plan type and AI usage limit information +* **Teams** - Manage team members, roles, and invites — the same controls available in **Settings** > **Teams** in the Warp app +* **AI** - Configure general and AI autonomy settings for your team +* **Models** - Configure which models are available to your team and AWS Bedrock +* **Code** - Enable Codebase Context for your team +* **Platform** - Configure Oz cloud agent settings +* **Privacy** - Configure user-generated content data collection, cloud conversation storage, and enterprise secret redaction +* **Sharing** - Configure direct link sharing and "anyone with link" sharing permissions + +### How settings enforcement works + +Settings configured in the Admin Panel are enforced at the team level: + +* **Enforced settings** - Cannot be overridden by individual users (e.g., BYOLLM routing policies) +* **Respect User Setting** - Defers to each user's own preference, letting individual team members configure that setting themselves + +## Step 5: Set up team resources + +### Enable Codebase Context + +Codebase Context indexes your Git repositories to help agents understand your code across large, multi-repo systems: + +1. Navigate to **Admin Panel** > **Code**. +2. Toggle **Codebase Indexing** to **Enabled**. + +Warp prompts team members to index repositories when they navigate to a Git-tracked directory. + +### Create shared Warp Drive resources + +Populate your team's Warp Drive with shared resources to scale best practices and compound productivity gains: + +* **Workflows** - Parameterized commands for common tasks (deployments, environment setup) +* **Notebooks** - Interactive runbooks for onboarding and operational procedures +* **Prompts** - Saved agent prompts for recurring tasks (code review, test generation) +* **Rules** - Coding standards and conventions that agents should follow +* **Environment Variables** - Shared configuration for development environments + +See [Warp Drive documentation](/knowledge-and-collaboration/warp-drive/) for details on creating team resources. + +### Configure MCP integrations + +Connect Warp to your team's tools for enhanced agent context. Navigate to **Settings** > **Agents** > **MCP servers** to get started. Some integrations (like Linear, GitHub, and Sentry) are available to enable with a single click, while you can also add any custom MCP server configuration your team needs. + +Once configured, click the share icon on a server to make it available to your team. + +See the [MCP documentation](/agent-platform/capabilities/mcp/) for full configuration details. + +## Next steps + +Once your team is set up: + +* **For developers** - Share the [Getting started for developers](/enterprise/getting-started/getting-started-developers/) guide with your team +* **Agent Profiles** - Configure default [Agent Profiles](/agent-platform/capabilities/agent-profiles-permissions/) for different types of work to give teams appropriate autonomy and control +* **BYOLLM** - Set up [Bring Your Own LLM](/enterprise/enterprise-features/bring-your-own-llm/) to route inference through your cloud infrastructure for data locality and cost control +* **Monitor usage** - Review usage analytics in the Admin Panel to track adoption and measure engineering productivity gains +* **Self-hosting** - Run Oz agents on your own infrastructure to control where agents run and keep repository clones on your own machines. See [Self-Hosting](/agent-platform/cloud-agents/self-hosting/) for setup instructions + +## Troubleshooting + +### SSO login issues + +For common SSO problems (login failures, account linking, provider portal errors), see [SSO troubleshooting](/enterprise/security-and-compliance/sso/#troubleshooting). + +### Team invite links not working + +**Common causes:** +* Invite link expired or was revoked +* User's email domain doesn't match configured restrictions + +**Solution:** +1. Generate a new invite link. +2. Verify domain restrictions match user's email. + +## Support and resources + +* [Admin Panel documentation](/enterprise/team-management/admin-panel/) +* [Troubleshooting login issues](/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/) +* [Contact enterprise support](https://warp.dev/contact-sales) - Priority support via dedicated Slack/Teams channel diff --git a/src/content/docs/enterprise/getting-started/quickstart.mdx b/src/content/docs/enterprise/getting-started/quickstart.mdx new file mode 100644 index 0000000..919a366 --- /dev/null +++ b/src/content/docs/enterprise/getting-started/quickstart.mdx @@ -0,0 +1,95 @@ +--- +title: Quick start +description: >- + Get up and running with Warp Enterprise in under 10 minutes. Log in, set up + your terminal, and run your first Oz agent. +--- + +This quickstart walks you through the essentials: logging in via SSO, setting up Warp, and running your first Oz agent. You can complete this in under 10 minutes. + +## Step 1: Log in via SSO + +1. Go to [app.warp.dev/login](https://app.warp.dev/login). +2. Click **Continue with SSO**. +3. Enter your work email or your organization's domain. +4. Complete authentication with your identity provider. + +:::caution +Do not launch Warp from your SSO provider's app portal (e.g., Okta dashboard). Always log in through [app.warp.dev/login](https://app.warp.dev/login). +::: + +If you have an existing Warp account from before your organization enabled SSO, [link it to SSO first](https://app.warp.dev/link_sso). + +## Step 2: Download and set up Warp + +1. Visit [warp.dev/download](https://warp.dev/download) and select your platform (macOS, Linux, or Windows). +2. Install Warp: + * **macOS** - Open the `.dmg` and drag Warp to Applications. + * **Linux** - Install via `.deb`, `.rpm`, or the install script. + * **Windows** - Run the `.exe` installer. +3. Launch Warp and log in with SSO (Step 1). +4. Verify you see your team name in **Settings** > **Teams**. + +## Step 3: Configure and run your first Oz agent + +When you use agents in Warp, you're using **Oz agents**. Oz is Warp's programmable agent for running and coordinating agents at scale, whether they run locally on your machine or in the cloud. + +### Index your codebase + +1. Navigate to a Git repository in Warp. +2. Warp automatically detects the repo and begins indexing. +3. Optionally, run `/init` to manually trigger indexing or re-indexing after significant code changes. +4. Once indexed, Oz agents understand your code structure, patterns, and conventions. + +### Run your first Oz agent locally + +Start an Oz conversation right in the terminal. Try the following prompt: + +``` +Explain the architecture of this project +``` + +Oz reads your codebase, understands its structure, and responds with a context-aware explanation. + +### Try more prompts + +* **Write code** - "Add input validation to the signup form" +* **Debug** - "Why is this test failing?" (paste the error output) +* **Explore** - "What patterns does this repo use for error handling?" +* **Plan** - Use `/plan` to have Oz create a structured task plan for complex features + +## Step 4: Run an Oz cloud agent + +Oz cloud agents run in the cloud for background work, unlimited parallelization, and long-running tasks. + +### Create an environment + +Environments define the execution context for cloud agents (repo access, dependencies, secrets, compute). You can create an environment in several ways: + +**Option 1: Slash command in Warp** + +From the Warp app terminal input, run the command: +``` +/create-environment +``` +This launches an interactive flow that guides you through environment setup. + +**Option 2: Oz web app** + +Go to [app.warp.dev/environments](https://app.warp.dev/environments) and click **Create Environment**. + +### Run a cloud agent + +Once your environment is ready, use the following command to launch a cloud agent (use the environment ID from above): + +```bash +oz agent run-cloud --env my-env --prompt "Review the open PRs in this repo" +``` + +Monitor and steer Oz cloud agents from the Oz dashboard or directly in Warp. + +## Next steps + +* **Set up key features** - Follow the full [Getting started for developers](/enterprise/getting-started/getting-started-developers/) guide to configure Codebase Context, Warp Drive, MCP integrations, and Agent Profiles. +* **Explore Oz cloud agents** - Learn about [Oz cloud agents](/agent-platform/cloud-agents/overview/) for background automation and parallel workflows. +* **Learn more** - Visit [Warp Guides](/guides/) for video tutorials and end-to-end workflows. diff --git a/src/content/docs/enterprise/index.mdx b/src/content/docs/enterprise/index.mdx new file mode 100644 index 0000000..b373bec --- /dev/null +++ b/src/content/docs/enterprise/index.mdx @@ -0,0 +1,89 @@ +--- +title: Enterprise overview +description: >- + Warp Enterprise provides the security, control, and collaboration features + organizations need to deploy Warp across their engineering teams at scale. +--- + +Warp Enterprise is built for organizations that want to accelerate software development with agents while maintaining security, compliance, and administrative control. It brings Warp's **Agentic Development Environment** to your entire engineering organization with the governance features IT and security teams require. + +Warp has two core products: + +* **Warp Terminal** - A modern terminal designed for agentic development where developers run commands, collaborate with agents, and orchestrate autonomous work from the command line. +* **Oz** - Warp's programmable agent for running and coordinating agents at scale. Oz powers all agents in Warp, whether they run locally or in the cloud, and provides the orchestration, tracking, and control plane for scalable agent workflows. + +## Who Warp Enterprise is for + +Warp Enterprise serves three primary audiences: + +* **IT admins and platform teams** - Deploy and manage Warp across your organization with SSO, centralized administration, and usage visibility +* **Engineering managers** - Give your teams powerful agent development tools while enforcing coding standards and best practices through shared team resources +* **Professional developers** - Accelerate your work across the entire SDLC with state-of-the-art agents, team knowledge sharing, and collaborative workflows that keep you in control + +## Key capabilities + +### Enterprise administration +* **Single Sign-On (SSO)** - Authenticate via your existing identity provider (Okta, Microsoft Entra ID, Google Workspace, and more) +* **Centralized Admin Panel** - Manage team settings, user permissions, and feature controls from one location +* **User roles and permissions** - Control access with Team Owner, Team Admin, and Member roles +* **Usage visibility** - Monitor team adoption and agent usage across your organization + +### Security and compliance +* **SOC 2 Type II certified** - Meets enterprise security and compliance requirements +* **Zero Data Retention (ZDR)** - No customer data is retained, stored, or used for training by contracted LLM providers +* **Open source client** - Warp's client code is published under [AGPL v3](https://github.com/warpdotdev/warp/blob/master/LICENSE) at [`warpdotdev/warp`](https://github.com/warpdotdev/warp) for security review and audit +* **Bring Your Own LLM (BYOLLM)** - Route inference through your own cloud infrastructure (AWS Bedrock) +* **Flexible deployment** - Choose Warp-hosted or hybrid deployment models +* **Telemetry controls** - Configure what data is collected at the team level + +### Team collaboration +* **Warp Drive team workspace** - Share Workflows, Notebooks, Prompts, Plans, Rules, and Environment Variables across your team +* **Codebase Context** - Team-level code indexing helps agents understand your repositories and generate accurate, context-aware responses +* **MCP integrations** - Connect to your team's tools (Linear, Sentry, Figma, GitHub, and more) for context-aware agent responses +* **Session sharing** - Collaborate on terminal sessions and Oz conversations with shareable links + +### Oz agent capabilities +* **State-of-the-art agents** - Multi-model agents with full terminal access, code editing, and autonomous task execution +* **Oz cloud agents** - Run agents in the cloud for unlimited parallelization, background automation, and long-running workflows. Perfect for PR reviews, scheduled tasks, and distributed work across multiple repositories +* **Integrated control plane** - Launch, orchestrate, and manage local, cloud, and autonomous agents from a unified interface. Track all agent activity across your team from the Oz dashboard +* **Agent Profiles** - Customize agent behavior, models, autonomy levels, and permissions +* **Rules and guardrails** - Enforce coding standards, tech stack preferences, and security practices through team-wide or project-specific rules +* **Multi-agent support** - Support for all major models and CLI coding agents (Oz, Claude Code, Codex, Copilot) + +## What this section covers + +This section organizes Enterprise documentation to help you deploy, secure, and scale Warp across your organization: + +* **Getting started** - Installation, SSO setup, and onboarding for admins and developers +* **Security and compliance** - Security overview and SSO configuration +* **Enterprise features** - Bring Your Own LLM (BYOLLM) +* **Team management** - Admin panel, roles and permissions, and access controls + +## Getting started + +:::note +Warp Enterprise is available through annual contracts. [Contact our sales team](https://warp.dev/contact-sales) to learn more or start a trial. +::: + +**For IT admins**: Start with the [Admin Panel](/enterprise/team-management/admin-panel/) to manage team settings, configure agent policies, and enforce security controls. See [Roles and permissions](/enterprise/team-management/roles-and-permissions/) for user access details. + +**For developers**: Jump to [Getting started for developers](/enterprise/getting-started/getting-started-developers/) to download Warp, log in, and start using key features like Codebase Context and Warp Drive. Or try the [Enterprise quickstart](/enterprise/getting-started/quickstart/) for a 10-minute walkthrough. + +**For security teams**: Review our [Security page](https://www.warp.dev/legal/security) and [Privacy documentation](/support-and-community/privacy-and-security/privacy/) to understand how Warp handles data, encryption, and compliance. + +## Why enterprises choose Warp + +Organizations adopt Warp Enterprise to: + +* **Accelerate development velocity** - Agents automate tedious tasks across the SDLC, from environment setup to incident response, so developers focus on what matters +* **Maintain security and control** - Deploy on your infrastructure, route inference through your cloud accounts, and keep developers in control with full visibility and guardrails +* **Scale best practices** - Share team knowledge, coding standards, and operational runbooks through Warp Drive to compound productivity gains across teams +* **Reduce context switching** - Keep developers in flow with a terminal-first environment that integrates agents, code editing, and tool integrations in one place +* **Get scaffolding built in** - Deploy agents at scale without building custom infrastructure—Warp provides orchestration, tracking, and collaboration out of the box + +## Support and resources + +* **Documentation** - Comprehensive guides throughout this enterprise section +* **Contact sales** - [Schedule a demo or start a trial](https://warp.dev/contact-sales) +* **Support** - Enterprise customers receive priority support via dedicated Slack/Teams channels +* **Warp Guides** - Video tutorials and training at [docs.warp.dev/guides](/guides/) diff --git a/src/content/docs/enterprise/security-and-compliance/security-overview.mdx b/src/content/docs/enterprise/security-and-compliance/security-overview.mdx new file mode 100644 index 0000000..d5f4068 --- /dev/null +++ b/src/content/docs/enterprise/security-and-compliance/security-overview.mdx @@ -0,0 +1,225 @@ +--- +title: Security overview +description: >- + Understand Warp's security architecture, data handling practices, and + compliance certifications to ensure your organization's requirements are + met. +--- + +Warp builds security and compliance into its core, keeping **developers in control** while enabling powerful agent workflows. This overview explains how Warp handles your data, what security controls are available, and how Warp meets enterprise security standards. + +## Transparency and control + +Warp's security philosophy centers on **transparency and developer control**: + +* **Complete visibility** - View exactly what telemetry is collected through our [exhaustive telemetry table](/support-and-community/privacy-and-security/privacy/#exhaustive-telemetry-table) +* **Real-time monitoring** - Use Warp's [Network Log](/support-and-community/privacy-and-security/network-log/) to monitor all network requests in real time +* **Opt-out controls** - Disable telemetry and crash reporting at any time while retaining full functionality +* **Team-level enforcement** - Admins can configure telemetry and data collection policies for the entire organization +* **Open source client** - Warp's client code is published under [AGPL v3](https://github.com/warpdotdev/warp/blob/master/LICENSE) at [`warpdotdev/warp`](https://github.com/warpdotdev/warp), so security teams can audit the codebase directly. See [Contributing to Warp](/support-and-community/community/contributing/) for the source repository and the security reporting process. + +## What telemetry does Warp collect and why? + +### Zero Data Retention (ZDR) + +Warp has **Zero Data Retention (ZDR)** agreements with its contracted LLM providers (Anthropic, OpenAI, Google), meaning they do not store or train on your data. ZDR applies across all Warp plans. + +How data collection works by plan: + +* **Free tier** - Individual users can disable data collection in **Settings** > **Privacy**. +* **Paid teams** - Team admins can enforce data collection settings for the entire team. Data collection is enabled by default. +* **Business and Enterprise** - Team admins can enforce data collection settings for the entire team. Data collection is **disabled by default**. + +:::note +Some product features — including cloud conversations and Oz runs — require storing conversation data to function. This data is stored to power the product experience and is separate from analytics or telemetry data collection. +::: + +Enterprise subscriptions also include: + +* **Team-level enforcement** - Admins configure data collection and telemetry policies for the entire organization through the Admin Panel +* **Secret redaction** - All AI interactions automatically apply [secret redaction](/support-and-community/privacy-and-security/secret-redaction/) to prevent sensitive data exposure + +### Telemetry categories + +When telemetry is enabled, Warp collects: + +1. **Product usage analytics** - High-level metrics on feature adoption and usage patterns (e.g., "Agent Mode was opened," "workflow was executed"). +2. **Performance and stability** - Crash reports, error tracking, and performance metrics to identify and fix issues. + +When data collection is disabled, Warp does not collect: + +* Personally identifiable information beyond user IDs and email addresses +* Network traffic or external API calls + +### Disabling telemetry + +Users can opt out of telemetry individually: + +1. Navigate to **Settings** > **Privacy**. +2. Toggle off **Help improve Warp** and/or **Send crash reports**. + +With telemetry disabled, Warp stops collecting usage and interaction data for analytics purposes. + +Team admins can enforce telemetry settings organization-wide through the Admin Panel. On Business and Enterprise plans, data collection is disabled by default. + +## Data handling and privacy + +### Where your data lives + +* **Code and files** - Stay on your machine unless you explicitly use features that transmit them (e.g., Codebase Context indexing, session sharing, Warp Drive team resources) +* **Codebase Context** - During indexing, code is sent to Warp's servers to generate embeddings; the raw code is not stored, only the resulting embeddings are retained +* **Agent requests** - Warp sends requests to contracted LLM providers (Anthropic, OpenAI, Google) with Zero Data Retention agreements for Enterprise teams +* **BYOLLM** - Requests are proxied through Warp's servers to your cloud infrastructure, where inference runs. Warp does not store the content of these requests. + +### Encryption + +* **In transit** - All data transmitted to Warp servers uses TLS 1.2 or higher +* **At rest** - Warp encrypts all user data at rest using AES-256 + +### Secret redaction + +Warp automatically detects and redacts sensitive information before sending any data to LLM providers, keeping developers in control of what gets shared: + +* API keys and tokens +* Passwords and secrets +* SSH keys and certificates +* Custom secret patterns (configurable via Admin Panel) + +See [Secret Redaction documentation](/support-and-community/privacy-and-security/secret-redaction/) for details. + +### Data retention + +* **ZDR** - Warp's contracted LLM providers do not retain or train on your data +* **Telemetry data** - When collected, Warp retains telemetry data indefinitely for analytics and debugging +* **User accounts** - Data deletion requests are processed securely within 30 days at no cost, following verified authentication and compliance with legal and contractual obligations + +## Compliance and certifications + +### SOC 2 Type II + +Warp is SOC 2 Type II certified, demonstrating compliance with industry-standard security controls for: + +* **Security** - Infrastructure protection, access controls, and monitoring +* **Availability** - System uptime and disaster recovery +* **Confidentiality** - Data protection and privacy controls +* **Processing integrity** - Accurate, complete, and authorized processing + +SOC 2 reports are available to Enterprise customers upon request. + +## Infrastructure security + +### Warp-hosted infrastructure + +When using Warp's hosted infrastructure: + +* **Cloud provider** - Hosted on GCP with SOC 2 and ISO 27001 certified datacenters +* **Network isolation** - Workloads run in isolated VPCs with strict network policies + +Warp's operational security practices — including access controls, monitoring, and vulnerability management — are validated through SOC 2 Type II certification. See [Compliance and certifications](#compliance-and-certifications) for details. + +### Self-hosted deployments + +Enterprise teams can self-host Oz cloud agent execution to control where agents run and keep repositories on their own infrastructure. + +Self-hosted deployments use a split architecture: +* **Execution plane (customer-hosted)** - Repository clones, build artifacts, runtime secrets, and container filesystem state stay on your infrastructure +* **Control plane (Warp-hosted)** - Session transcripts (which include code context from agent interactions), orchestration metadata, and LLM inference route through Warp's servers under Zero Data Retention (ZDR) agreements. Warp does not persistently store your source code or use it for model training + +Two deployment modes are available: +* **Unmanaged** - Use `oz agent run` to run agents in your existing orchestrator or CI environment. Supports Linux, macOS, and Windows with no Docker dependency. +* **Managed** - Run the `oz-agent-worker` daemon to let the Oz platform orchestrate agents in isolated Docker containers on your infrastructure. + +Agent runs are fully tracked and steerable in both modes. No inbound network access is required. + +**Network egress requirements** + +Self-hosted agents require outbound access to Warp's backend services and, for the managed architecture, Docker Hub and GitHub. + +## Access controls and authentication + +### Single Sign-On (SSO) + +Warp supports SSO via Okta, Microsoft Entra ID, Google Workspace, OneLogin, and any SAML 2.0 or OpenID Connect (OIDC) compatible provider. Admins can require SSO for all team members and enforce MFA through your identity provider. + +See [Single Sign-On (SSO)](/enterprise/security-and-compliance/sso/) for setup instructions, SCIM provisioning, account linking, and troubleshooting. + +### Team permissions + +Warp uses role-based access control with three roles — Team Owner, Team Admin, and Member — to manage team access and Admin Panel privileges. See [User roles and permissions](/enterprise/getting-started/getting-started-enterprise/#user-roles-and-permissions) for details. + +Resource sharing in Warp Drive has granular controls for who can view, edit, and share. + +### Admin Panel governance + +The Admin Panel gives security and IT teams centralized control over AI behavior, data handling, and sharing policies. Settings can be **enforced** (overriding individual user preferences organization-wide) or set to **respect user setting** (deferring to individual preferences). + +Security-relevant controls include: +* **Privacy** - Configure user-generated content (UGC) data collection, cloud conversation storage, and enterprise secret redaction +* **Sharing** - Restrict or permit direct link sharing and "anyone with link" sharing permissions +* **AI** - Configure AI autonomy settings and general agent behavior for the team +* **Models** - Control which LLM models are available to team members, including AWS Bedrock +* **Platform** - Configure Oz cloud agent access and settings + +## Security features for developers + +### Bring Your Own LLM (BYOLLM) + +Route agent inference through your own cloud infrastructure for complete control: + +* **Data locality** - Cloud agent inference runs in your AWS account +* **Cloud-native IAM** - Authenticate using your user's existing identity and access management process +* **No key storage** - Warp never stores your cloud credentials or API keys +* **Billing control** - Inference costs billed directly to your cloud account + +See [Bring Your Own LLM](/enterprise/enterprise-features/bring-your-own-llm/) for configuration details. + +### Docker Sandboxes + +Isolate agent execution in containerized environments: + +* **Process isolation** - Agents run in separate Docker containers, isolated from your host system +* **Resource limits** - Configure CPU, memory, and disk quotas per sandbox +* **Network controls** - Restrict outbound network access from sandboxes +* **Ephemeral environments** - Sandboxes are destroyed after use, leaving no trace + +### Agent permissions + +Configure what agents can access and execute: + +* **Tool restrictions** - Enable/disable terminal use, code editing, web search, and file system access +* **Repository scoping** - Limit agents to specific repositories or directories +* **Execution approvals** - Require manual approval for sensitive commands +* **Visibility** - When cloud conversation storage is enabled, agent actions are logged with full context for review + +## Incident response and support + +### Security issue reporting + +If you discover a security vulnerability in Warp: + +1. Email [security@warp.dev](mailto:security@warp.dev). +2. Include detailed steps to reproduce. +3. Do not publicly disclose until Warp has addressed the issue. + +Warp follows responsible disclosure practices and works with reporters to coordinate disclosure timelines. + +### Enterprise support + +Enterprise customers receive priority security support: + +* **Dedicated channels** - Private Slack/Teams channels for security questions +* **Security advisories** - Proactive notifications of security updates +* **Incident assistance** - Support during security incidents or breach investigations +* **Compliance assistance** - Help with compliance questionnaires and audits + +## Additional resources + +* **Privacy policy** - [warp.dev/legal/privacy-policy](https://www.warp.dev/legal/privacy-policy) +* **Trust center** - [trust.warp.dev](https://trust.warp.dev) — security documentation and compliance reports. See also [Trust Center](/enterprise/security-and-compliance/trust-center/) for details on requesting SOC 2 reports, subprocessors, and vendor security assessments. +* **Subprocessors** - [warp.dev/legal/subprocessors](https://www.warp.dev/legal/subprocessors) +* **Privacy documentation** - [Privacy guide](/support-and-community/privacy-and-security/privacy/) with complete telemetry table +* **Contact** - [privacy@warp.dev](mailto:privacy@warp.dev) for privacy questions, [security@warp.dev](mailto:security@warp.dev) for security issues + +:::note +For vendor security assessments, compliance questionnaires, or access to SOC 2 reports, contact your account manager or email [security@warp.dev](mailto:security@warp.dev). +::: diff --git a/src/content/docs/enterprise/security-and-compliance/sso.mdx b/src/content/docs/enterprise/security-and-compliance/sso.mdx new file mode 100644 index 0000000..d591622 --- /dev/null +++ b/src/content/docs/enterprise/security-and-compliance/sso.mdx @@ -0,0 +1,110 @@ +--- +title: Single Sign-On (SSO) +description: >- + Configure Single Sign-On (SSO) to authenticate and manage access to Warp + across your organization. +--- + +Warp uses SSO to authenticate users and control access to your organization's Warp team. This guide covers configuring SSO, testing your setup, and managing user access through your identity provider. + +## Supported identity providers + +Warp supports the following identity providers: + +* **Okta** +* **Microsoft Entra ID** +* **Google Workspace** +* **OneLogin** +* **Any SAML 2.0 or OpenID Connect (OIDC) compatible provider** + +## SSO enforcement and session management + +* **SSO enforcement** - Admins can require SSO for all team members, preventing login via other methods. +* **Multi-factor authentication** - MFA is enforced through your identity provider's policies. Warp respects MFA requirements configured in Okta, Microsoft Entra ID, Google Workspace, etc. +* **Session management** - Configurable session timeouts and re-authentication policies through your identity provider. + +## Setting up SSO + +SSO is configured through [WorkOS](https://workos.com) in coordination with Warp's team: + +1. Contact your Warp account team or [enterprise support](https://warp.dev/contact-sales) to initiate SSO setup. +2. Warp creates an organization for your team in WorkOS and sets your team domain. +3. Your IT admin receives an email invite from WorkOS. +4. Follow the WorkOS setup wizard to connect your identity provider (configure SAML attributes or OAuth scopes, provide your SSO URL and certificate). +5. Once complete, team members can log in via **Continue with SSO** at [app.warp.dev/login](https://app.warp.dev/login). + +:::note +After enabling SSO, existing users who signed up with email or OAuth need to link their accounts. See [Linking existing accounts](#linking-existing-accounts) below. +::: + +## Testing SSO + +Before rolling out to your team: + +1. Open an incognito/private browser window. +2. Navigate to [app.warp.dev/login](https://app.warp.dev/login). +3. Click **Continue with SSO**. +4. Enter your organization's domain. +5. Verify you're redirected to your identity provider and can log in successfully. + +:::caution +Warp cannot be launched directly from your SSO provider's app portal (e.g., Okta dashboard). Users must log in through [app.warp.dev/login](https://app.warp.dev/login) and select **Continue with SSO**. +::: + +## SCIM provisioning + +Warp supports SCIM for user lifecycle management. Provisioning works through Just-In-Time (JIT) provisioning combined with SSO and domain capture: + +* **User provisioning** - Add users to the Warp application in your identity provider. Once they sign in via SSO, they are automatically added to your Warp team. +* **Domain auto-join** - Users who sign in with SSO from your configured domain are automatically joined to your team. See [Domain auto-join](#domain-auto-join) for setup details. +* **User deprovisioning** - Removing a user from the Warp application in your identity provider prevents future SSO logins. Existing sessions are not immediately revoked. + +:::note +Warp does not currently support SCIM group sync. User provisioning is handled via JIT — users appear in your Warp team after their first SSO login, not at the time they are assigned in your identity provider. +::: + +## Linking existing accounts + +Users who created a Warp account before your organization enabled SSO need to link their accounts: + +1. Log in to Warp with the original method (email, Google, or GitHub). +2. Navigate to [app.warp.dev/link_sso](https://app.warp.dev/link_sso). +3. Complete the linking process. +4. Log out and log back in with **Continue with SSO**. + +## Domain auto-join + +Domain auto-join allows users from your organization to automatically join your Warp team after SSO authentication. + +:::note +Domain configuration is set up by the Warp team during onboarding. Contact your Warp account team to configure or update your team domain. +::: + +Once your team domain is configured, users who sign in via SSO from your domain are automatically added to your Warp team. + +## Troubleshooting + +### Users can't log in with SSO + +**Common causes:** +* SSO not properly configured in your identity provider. +* User trying to launch Warp directly from SSO provider (not supported). +* User has an existing Warp account that needs to be [linked to SSO](https://app.warp.dev/link_sso). + +**Solution:** +1. Verify SSO configuration in your identity provider. +2. Have users log in through [app.warp.dev/login](https://app.warp.dev/login) and select **Continue with SSO**. +3. For existing accounts, follow the [SSO linking process](https://app.warp.dev/link_sso). + +### Warp won't open from SSO provider portal + +**Problem:** Clicking Warp in Okta/Microsoft Entra ID portal shows an error. + +**Solution:** +Log in directly through [app.warp.dev/login](https://app.warp.dev/login) and select **Continue with SSO** instead. + +## Related resources + +* [Security overview](/enterprise/security-and-compliance/security-overview/) - Enterprise security posture and compliance +* [Getting started for admins](/enterprise/getting-started/getting-started-enterprise/) - Full admin onboarding guide +* [Troubleshooting login issues](/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/) diff --git a/src/content/docs/enterprise/security-and-compliance/trust-center.mdx b/src/content/docs/enterprise/security-and-compliance/trust-center.mdx new file mode 100644 index 0000000..d5cbaa5 --- /dev/null +++ b/src/content/docs/enterprise/security-and-compliance/trust-center.mdx @@ -0,0 +1,63 @@ +--- +title: Trust Center +description: >- + Access Warp's security documentation, compliance certifications, and + third-party assessment resources to complete your vendor security review. +--- + +Warp's [Trust Center](https://trust.warp.dev) is the central hub for security documentation, compliance certifications, and third-party assessments. It provides the information security teams, procurement, and compliance officers need to evaluate Warp as a vendor and complete security reviews. + +## Compliance certifications + +### SOC 2 Type II + +Warp is **SOC 2 Type II certified**, demonstrating compliance with industry-standard security controls across the following trust service criteria: + +* **Security** - Infrastructure protection, access controls, and monitoring +* **Availability** - System uptime and disaster recovery +* **Confidentiality** - Data protection and privacy controls +* **Processing integrity** - Accurate, complete, and authorized processing + +**Requesting SOC 2 reports:** Enterprise customers can request SOC 2 reports directly through the [Trust Center portal](https://trust.warp.dev), through their account manager, or by emailing [security@warp.dev](mailto:security@warp.dev). + +## Subprocessors + +Warp publishes a list of subprocessors — third-party service providers that process data on Warp's behalf. This includes infrastructure providers, LLM providers, and other services that support Warp's operations. + +View the current list of subprocessors at [warp.dev/legal/subprocessors](https://www.warp.dev/legal/subprocessors). + +:::note +Warp maintains **Zero Data Retention (ZDR)** agreements with its contracted LLM providers (Anthropic, OpenAI, Google), meaning they do not store or train on your data. +::: + +## Security documentation + +The following resources provide detailed information about Warp's security practices: + +* **[Trust Center portal](https://trust.warp.dev)** - External portal with downloadable compliance reports and real-time security status +* **[Security overview](/enterprise/security-and-compliance/security-overview/)** - Warp's security architecture, data handling, and compliance certifications +* **[Privacy policy](https://www.warp.dev/legal/privacy-policy)** - How Warp collects, uses, and protects personal data +* **[Subprocessors](https://www.warp.dev/legal/subprocessors)** - Third-party service providers that process data on Warp's behalf + +## Requesting security information + +If you're conducting a vendor security assessment or completing a compliance questionnaire, Warp can provide: + +* **SOC 2 Type II reports** - Available upon request for Enterprise customers +* **Compliance questionnaire assistance** - Warp's security team can help complete vendor security questionnaires +* **[Architecture and deployment](/enterprise/enterprise-features/architecture-and-deployment/)** - Details about Warp's infrastructure, deployment models, and data flows + +To request any of these materials, contact your account manager or email [security@warp.dev](mailto:security@warp.dev). + +## Penetration testing and vulnerability management + +Warp conducts regular security assessments as part of its SOC 2 program. The details of Warp's vulnerability management and penetration testing practices are validated through its SOC 2 Type II certification. + +### Responsible disclosure + +If you discover a security vulnerability in Warp, please report it responsibly: + +1. Email [security@warp.dev](mailto:security@warp.dev) with detailed steps to reproduce the issue. +2. Allow Warp time to investigate and address the vulnerability before any public disclosure. + +Warp works with reporters to coordinate disclosure timelines. diff --git a/src/content/docs/enterprise/support-and-resources/billing.mdx b/src/content/docs/enterprise/support-and-resources/billing.mdx new file mode 100644 index 0000000..c3c6b7c --- /dev/null +++ b/src/content/docs/enterprise/support-and-resources/billing.mdx @@ -0,0 +1,87 @@ +--- +title: Billing +description: >- + Learn about billing for Warp Enterprise, including credits, cloud agent + costs, and billing management. +--- + +This page covers general information about credits, cloud agent costs, and BYOLLM billing for enterprise teams. If you have specific questions about custom pricing, credit allocation, or contract terms, contact your Warp account manager. + +## Credits + +Warp uses a credit-based billing model. Any interaction with Oz agents consumes credits based on the complexity of the task, the model used, and the amount of context processed. + +### How credits work + +* Each agent interaction consumes **at least one credit**, though complex interactions may use multiple credits. +* Credit usage is influenced by the LLM model used, the number of tool calls, task complexity, amount of context, and prompt caching behavior. +* Credit usage is **non-deterministic**. Two similar prompts may consume different numbers of credits. + +For details on how credits are calculated, see [Credits](/support-and-community/plans-and-billing/credits/). + +### Credit allocation + +Enterprise plans include a custom team-wide credit pool as part of your contract. Credits are primarily shared across the entire team rather than allocated per seat. Individual credit grants may also occur (e.g., support refunds), but the core allocation is team-wide. + +:::note +Credit allocations vary by contract. Contact your account manager for details on your team's specific allocation. +::: + +## Cloud agent billing + +Oz cloud agents consume credits that include a small hosting fee in addition to AI usage costs. + +### How credits are consumed + +On Enterprise plans, both local and cloud agent usage draw from the same team credit pool. There are no separate "cloud agent credits" or "local credits" — all agent usage consumes from your available credit sources. + +For team API key runs (e.g., CI/CD pipelines, scheduled tasks), credits also draw from the team's shared pool since these runs are not tied to any individual user. + +For more details, see [Access, Billing, and Identity](/agent-platform/cloud-agents/team-access-billing-and-identity/). + +## BYOLLM billing + +When using [Bring Your Own LLM (BYOLLM)](/enterprise/enterprise-features/bring-your-own-llm/), Warp routes requests through your cloud infrastructure (AWS Bedrock, Google Vertex, or Azure Foundry). BYOLLM requests **consume credits at a reduced rate** which is approximately 80% slower than standard usage. Inference costs are also billed directly to your cloud account. + +If a BYOLLM request fails and Warp falls back to a direct API model, that fallback request consumes Warp credits at the standard rate. + +## Managing billing + +Your Warp account manager handles all billing for your Enterprise contract. Contact your account manager or dedicated Slack/Teams channel for: + +* Invoices and payment changes +* Contract modifications +* Credit allocation adjustments + +For urgent billing issues, email [billing@warp.dev](mailto:billing@warp.dev). + +### Spending controls + +Administrators can configure monthly spending limits and receive alerts to prevent unexpected charges. Configure these controls in the [Admin Panel](https://app.warp.dev/admin/) under the **Billing** tab. + +#### Monthly spending limits + +Enterprise administrators can set monthly spending limits across the following four categories: + +* **Cloud spending limit** - Cap monthly spend on Oz cloud agent usage. +* **Local spending limit** - Cap monthly spend on local agent usage in the Warp app. +* **Total spending limit** - Cap combined monthly spend across both cloud and local agents. +* **Per-user spending limit** - Cap monthly spend for any individual user. Set a default that applies to all users, or configure limits on a per-user basis for predictable individual spend. + +Spending is tracked across all payment types (Add-on Credits, pay-as-you-go usage) so limits apply consistently regardless of how usage is funded. + +#### Monthly spend alerts + +Warp sends alerts to administrators as team usage approaches each configured spending limit, so you can adjust caps, purchase more credits, or communicate with your team before agent usage is blocked at the cap. + +#### Credit pool depletion alerts + +For enterprises with credit pools, administrators receive alerts as the team credit pool approaches full consumption. This gives you time to top up your credits or change your reload configuration before agent usage is interrupted for the entire team. + +## Related resources + +* [Credits](/support-and-community/plans-and-billing/credits/) - How credits are calculated and consumed +* [Add-on Credits](/support-and-community/plans-and-billing/add-on-credits/) - Purchase additional credits and configure auto-reload +* [Pricing FAQs](/support-and-community/plans-and-billing/pricing-faqs/) - Common billing questions +* [Bring Your Own LLM](/enterprise/enterprise-features/bring-your-own-llm/) - BYOLLM billing and configuration +* [Admin Panel](/enterprise/team-management/admin-panel/) - Configure spending limits and billing settings diff --git a/src/content/docs/enterprise/support-and-resources/feedback-and-feature-requests.mdx b/src/content/docs/enterprise/support-and-resources/feedback-and-feature-requests.mdx new file mode 100644 index 0000000..ad0d0ed --- /dev/null +++ b/src/content/docs/enterprise/support-and-resources/feedback-and-feature-requests.mdx @@ -0,0 +1,65 @@ +--- +title: Feedback and feature requests +description: >- + Report bugs, request features, and get support as a Warp Enterprise + customer. +--- + +Warp Enterprise customers have access to dedicated support channels for reporting issues, requesting features, and getting help. This page explains how to reach the right team and provide the information needed to resolve issues quickly. + +## Enterprise support channels + +Enterprise customers receive **priority support** through dedicated channels: + +* **Dedicated Slack or Teams channel** - Your primary support channel. A private channel shared with Warp engineers for real-time assistance, bug reports, and feature discussions. +* **Account manager** - Your direct contact for escalations, strategic feature requests, and enterprise-specific questions. + +:::note +For the fastest response, use your dedicated Slack or Teams channel. Warp engineers monitor these channels during business hours. +::: + +## Reporting bugs + +When reporting a bug, include the following to help Warp's team investigate quickly: + +1. **Description** - What happened and what you expected to happen. +2. **Steps to reproduce** - How to trigger the issue. +3. **Debugging ID** (for Agent issues) - Right-click on the Agent conversation block in question, select **Copy debugging ID**, and include it in your report. When an Agent conversation produces an error, an option to copy the debugging ID also appears inline. See [Gathering debugging ID](/support-and-community/troubleshooting-and-support/sending-us-feedback/#gathering-ai-debugging-id) for more details. +4. **Logs** (if relevant) - See [Gathering logs](#gathering-logs) below. +5. **Environment details** - OS, Warp version, and any relevant configuration. + +:::note +Most Enterprise teams have user-generated content (UGC) collection disabled, which limits the diagnostic information available from debugging IDs. Logs and detailed reproduction steps are especially important for Enterprise bug reports. +::: + +### Gathering logs + +Warp's logs do not contain console input or output. Log file locations by platform: + +* **macOS** - `~/Library/Logs/warp.log*` +* **Windows** - `%LOCALAPPDATA%\warp\Warp\data\logs\warp.log*` +* **Linux** - `~/.local/state/warp-terminal/warp.log*` + +You can also access logs directly in the app: open the **Command Palette** (`⌘P` on macOS / `Ctrl+Shift+P` on Windows/Linux) and search for **View Warp Logs**. + +For detailed log gathering instructions, including how to zip logs and capture crash reports, see [Sending Feedback & Logs](/support-and-community/troubleshooting-and-support/sending-us-feedback/). + +## Requesting features + +To request a new feature or enhancement: + +* **Enterprise customers** - Share feature requests through your dedicated Slack/Teams channel or with your account manager. This ensures your request is tracked and prioritized by the product team. +* **Public feature requests** - Open an issue on [GitHub Issues](https://github.com/warpdotdev/warp/issues/new/choose) for visibility and community discussion. + +## Specialized contacts + +For security or privacy inquiries, reach out to the appropriate team directly: + +* **Security issues** - [security@warp.dev](mailto:security@warp.dev) +* **Privacy questions** - [privacy@warp.dev](mailto:privacy@warp.dev) + +For all other inquiries — including billing, technical issues, and feature requests — contact your account manager or dedicated Slack/Teams channel. + +## Related resources + +* [Troubleshooting login](/enterprise/support-and-resources/troubleshooting-login/) - Resolve login and SSO issues diff --git a/src/content/docs/enterprise/support-and-resources/troubleshooting-login.mdx b/src/content/docs/enterprise/support-and-resources/troubleshooting-login.mdx new file mode 100644 index 0000000..52d7b00 --- /dev/null +++ b/src/content/docs/enterprise/support-and-resources/troubleshooting-login.mdx @@ -0,0 +1,108 @@ +--- +title: Troubleshooting login +description: >- + Resolve common login and SSO issues for Warp Enterprise users and IT admins. +--- + +This page covers common login issues for Warp Enterprise users, with a focus on SSO-related problems. For SSO setup and configuration, see [Single Sign-On (SSO)](/enterprise/security-and-compliance/sso/). + +## SSO login issues + +### Can't open Warp from your SSO provider + +When launching Warp directly from Okta or another SSO provider's app dashboard, you may see an error like "Unable to process request due to missing initial state." This is a known limitation with the authentication flow. + +**To fix it:** + +1. Go to [app.warp.dev/login](https://app.warp.dev/login). +2. Choose **Continue with SSO**. +3. Log in with your normal SSO credentials. + +### Previously logged in with another method + +If you originally created your Warp account with email, Google, or GitHub and now need to use SSO: + +1. Go to [app.warp.dev/login](https://app.warp.dev/login). +2. Log in with your **original** method (email, Google, or GitHub). +3. Once logged in, visit [app.warp.dev/link_sso](https://app.warp.dev/link_sso). +4. Click **Link SSO** to connect your existing account. You can now use **Continue with SSO** going forward. + +:::note +IT admins: if multiple team members need to link their accounts to SSO, share these steps during your SSO rollout. +::: + +## Common login issues + +### Can't sign up or log in + +If clicking the sign-up or login button opens a blank popup or nothing happens: + +* Your ISP or firewall may be blocking calls to `*.googleapis.com`. Try using a proxy or allowlisting this domain. +* In some older Ruby development environments, `.dev` domains don't resolve properly. If applicable, delete `/etc/resolver/dev` ([more info](https://superuser.com/questions/1374892/dev-domains-dont-resolve)). + +### Browser-specific issues + +If you see authentication errors or blank popups across browsers: + +1. **Disable ad blockers** for `app.warp.dev`. +2. **Clear cookies and cache**, or try an incognito / private browser window. +3. Try [app.warp.dev/login](https://app.warp.dev/login) again. + +**Safari-specific:** If you see "Unable to access localStorage" errors, go to **Safari Preferences** > **Privacy** and uncheck **Block all cookies**. Firebase Auth requires cookies to track login state. + +## Proxy issues + +If you're behind a proxy, QUIC traffic may not pass through correctly. Disabling QUIC in your browser forces a fallback to TCP, which typically resolves the issue: + +**Chrome / Chromium-based browsers (Edge, Opera, Arc):** +1. Navigate to `chrome://flags`. +2. Search for **Experimental QUIC protocol**. +3. Set it to **Disabled**. +4. Relaunch the browser. + +**Firefox:** +1. Navigate to `about:config`. +2. Accept the risk warning. +3. Search for `network.http.http3.enable`. +4. Double-click to set it to `false`. +5. Restart Firefox. + +**Safari:** There is no built-in option to disable QUIC in Safari. + +## Flagged as fraudulent + +If you see "This account has been flagged as fraudulent," your account has triggered Warp's fraud detection system. This can happen due to multiple account creation or use of throwaway emails (both against Warp's [Terms of Service](https://www.warp.dev/terms-of-service)). + +### False positives + +Ad blockers or systems like Pi-hole can sometimes trigger false positives. Try temporarily disabling them and attempting login again. + +### Requesting an appeal + +If you're still unable to authenticate, email [appeals@warp.dev](mailto:appeals@warp.dev) with the email address of the affected account. Appeals may take 5–10 days. + +Enterprise customers can also contact their account manager or dedicated Slack/Teams channel for faster resolution. + +## Browser doesn't open when signing in + +If the browser doesn't open automatically from Warp when you click "Sign up" or "Sign in": + +1. Go to the [Signup](https://app.warp.dev/signup) or [Login](https://app.warp.dev/login) page in your browser. +2. Complete authentication in the browser. +3. On the logged-in page, if "Take me to Warp" doesn't work, click the **here** link to copy the authentication token. +4. Paste the token into Warp. + +:::note +On Linux and Windows, the default paste shortcut is `CTRL+SHIFT+V`. +::: + +## Getting help + +* **Enterprise customers** - Contact your dedicated Slack/Teams channel or account manager. +* **All other users** - Visit [warp.dev/contact](https://www.warp.dev/contact) for support. + +## Related resources + +* [Single Sign-On (SSO)](/enterprise/security-and-compliance/sso/) - SSO setup and configuration +* [Feedback and feature requests](/enterprise/support-and-resources/feedback-and-feature-requests/) - Report bugs and request features +* [Troubleshooting login (full guide)](/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/) - Complete troubleshooting reference diff --git a/src/content/docs/enterprise/team-management/admin-panel.mdx b/src/content/docs/enterprise/team-management/admin-panel.mdx new file mode 100644 index 0000000..993e94e --- /dev/null +++ b/src/content/docs/enterprise/team-management/admin-panel.mdx @@ -0,0 +1,361 @@ +--- +title: Admin Panel +description: >- + Centralized management for team administrators to configure Warp settings, + control agent behavior, and enforce security policies across your + organization. +--- + +The Admin Panel provides administrators with centralized control over team settings in Warp. Configure agent behavior, security policies, codebase indexing, and collaboration features for your entire organization from a single interface. + +## What is the Admin Panel? + +The [Admin Panel](https://app.warp.dev/admin/) is your control center for managing Warp at scale. It allows IT admins, platform teams, and engineering managers to: + +* **Control agent behavior** - Set autonomy levels, command permissions, and safety guardrails organization-wide +* **Enforce security policies** - Configure secret redaction, telemetry controls, and data handling +* **Manage team resources** - Enable Codebase Context, configure BYOLLM, and control sharing permissions +* **Monitor usage** - Track credit consumption and set spending limits +* **Maintain compliance** - Apply consistent policies that meet your organization's security requirements + +:::note +Warp restricts Admin Panel access to team administrators. Regular team members can view settings that affect them but cannot modify organization-wide policies. +::: + +## Accessing the Admin Panel + +### For team admins + +Access the Admin Panel in two ways: + +**Option 1: Direct URL** +1. Navigate to [app.warp.dev/admin](https://app.warp.dev/admin/). +2. Log in with your SSO credentials. +3. The Admin Panel opens with all organization settings. + +**Option 2: From Warp Settings** +1. Open Warp and click your profile icon in the top right. +2. Click **Settings**. +3. Navigate to the **Admin Panel** tab (visible only to team admins). + +### For team members + +Team members see organization-enforced settings in their personal Settings panel: + +* Settings controlled by admins appear grayed out +* Indicated by message: "Your organization has configured this setting" +* Users retain control over settings where admins have selected "Respect User Setting" + +## How settings enforcement works + +The Admin Panel uses a three-tier enforcement model that keeps administrators in control while allowing appropriate flexibility. + +### Setting enforcement levels + +**Organization enforced** +* Setting applies to all team members regardless of individual preferences +* Users cannot override these settings +* Use for security-critical policies (e.g., secret redaction, command denylists) + +**Respect user setting** +* Allows individual team members to control the setting themselves +* Admins set a default, but users can customize +* Use for preferences that don't impact security or compliance (e.g., AI model selection) + +**Tier restricted** +* Setting is locked based on billing plan +* Cannot be changed until plan is upgraded +* Indicated by message: "Configuring this setting is not available on your plan" + +### Testing before enforcement + +:::note +Changes made in the Admin Panel take effect immediately for all team members. Test settings in your own Warp environment before applying organization-wide enforcement. +::: + +To safely roll out new policies: + +1. Configure settings with "Respect User Setting" initially. +2. Test with a small group of users. +3. Gather feedback and adjust configuration. +4. Switch to "Organization enforced" once validated. + +## Plan limitations + +The features available in the Admin Panel scale with your Warp plan: + +### Free tier +* Most settings are fixed and non-configurable +* Limited Codebase Context (2 repositories) +* No BYOLLM support +* Basic sharing features + +### Business plans +* Most settings become configurable by administrators +* Enhanced agent autonomy control +* Advanced sharing and privacy features +* Increased Codebase Context limits + +### Enterprise plans +* **Full admin control** - Configure all available settings +* **Enterprise secret redaction** - Custom regex patterns for secrets +* **BYOLLM** - Route inference through your cloud infrastructure +* **Self-hosting cloud agent workers** - Deploy Oz cloud agent workers on your own infrastructure +* **Advanced compliance** - SOC 2, HIPAA, and custom data handling agreements +* **Priority support** - Dedicated Slack/Teams channels + +For complete plan details, visit [warp.dev/pricing](https://www.warp.dev/pricing) or [contact sales](https://warp.dev/contact-sales). + +## Admin Panel sections + +The Admin Panel is organized into six main areas: + +### AI settings + +Configure how agents behave across your organization, including autonomy levels and command permissions. This is where you balance agent productivity with organizational safety requirements. + +#### General AI settings + +**AI in remote sessions** +* Controls whether agents are available during SSH sessions and remote connections +* Enterprise plans can toggle this setting +* Consider disabling for production servers or sensitive environments + +**Prompt summarization caching** +* When conversations become long, the LLM provider caches summaries temporarily +* Improves performance for extended agent interactions +* Zero Data Retention agreements cover caching (short-lived) + +#### Autonomy settings + +Configure how much independence agents have when performing actions. Choose between: + +* **Agent Decides** - Agent acts autonomously when confident, asks when uncertain (recommended) +* **Always Ask** - Require explicit approval for every action +* **Always Allow** - Maximum autonomy without confirmations +* **Respect User Setting** - Allow individual users to set their preference + +**Apply code diffs** +Controls whether agents can apply code changes without approval. For production-critical codebases, consider "Always Ask" to maintain tight control. + +**Create plans** +Whether agents can create structured task plans (`/plan` command) without user approval. + +**Execute commands** +Manages the agent's ability to run terminal commands autonomously. Pair with command allowlists/denylists for granular control. + +**Read files** +Controls agent access to reading files in the codebase. Enable for better context, restrict for sensitive repositories. + +#### Directory and command control + +**Directory allowlist** +Specify directories where agents can read files without restriction. Use absolute paths: +* `~/git/internal-tooling` - Grant access to specific projects +* `/home/user/repos/public-*` - Use wildcards for patterns + +**Command allowlist** +Regular expressions matching commands agents can execute without asking permission. Common patterns: +* `grep .*` - Text search +* `ls(\\s.*)?` - Directory listing +* `git status` - Version control queries +* `which .*` - Finding executables + +**Command denylist** +Regular expressions for commands that **always** require explicit user approval, regardless of autonomy settings: +* `rm -rf.*` - Recursive deletion +* `sudo.*` - Administrative commands +* `curl.*|wget.*` - Network requests +* `docker rm.*` - Container operations +* `.*production.*` - Commands containing "production" + +:::caution +Command denylist rules take precedence over allowlist rules and agent autonomy settings. Use denylists to prevent high-risk operations even in high-autonomy configurations. +::: + +### Privacy settings + +Manage data collection and security policies to meet your organization's compliance requirements. + +**User-generated content (UGC) data collection** +Controls how Warp collects and uses user-generated content to improve the service: +* **Disabled** - Warp collects no UGC data from your organization +* **Enabled** - Allow data collection for service improvement +* **Respect User Setting** - Let individual users decide + +Enterprise teams with Zero Data Retention agreements can disable this completely. + +**Enterprise secret redaction** +Automatically detects and redacts sensitive information before sending data to LLM providers: +* Enterprise plans enable this by default +* Includes automatic detection of common secret patterns (API keys, passwords, certificates) +* Supports custom regex patterns for organization-specific secrets +* Applies unconditionally across all team members + +Configure custom patterns in the Admin Panel to match your organization's secret formats. + +### Code settings + +Control codebase indexing and agent code features for your team. + +**Codebase Context** +Determines whether Warp indexes your team's Git repositories to provide context for agents: +* **Disabled** - No codebase indexing +* **Enabled** - Index codebases for improved agent responses across large, multi-repo systems +* **Respect User Setting** - Allow individual control + +When enabled, agents understand your code patterns, architecture, and conventions across all indexed repositories. Enterprise plans support: +* Unlimited repositories +* Up to 200,000 files per repository +* Team-wide indexing with centralized configuration + +### Billing settings + +Configure billing preferences and spending controls to manage costs at scale. + +**Usage-based pricing** +Enable pay-as-you-go billing for credits beyond your plan's included quota: +* Set monthly spending limits to control costs +* View current overage usage and costs +* Receive alerts when approaching spending thresholds + +**Credit allocation** +For Enterprise plans with negotiated credit pools: +* Allocate credits across teams or projects +* Monitor usage by team +* Set per-team spending limits + +Contact your account manager to configure advanced credit allocation. + +### Sharing settings + +Control how team members collaborate and share Warp Drive resources. + +**Direct link sharing** +Allow team members to share Notebooks, Workflows, Prompts, and other Warp Drive objects via direct links: +* **Enabled** - Team members can generate shareable links +* **Team only** - Links work only for team members +* **Disabled** - No link sharing + +**Anyone with link sharing** +Enable public access to shared objects: +* **Enabled** - Anyone with the link can view content without being a team member +* **Disabled** - Links require team membership to access + +For organizations with sensitive internal processes, disable "Anyone with link" sharing to prevent accidental exposure. + +### Platform settings + +Configure Oz cloud agent settings for your team, including GitHub authorization for automated workflows. + +**Enabled GitHub Orgs** + +The **Enabled GitHub Orgs** setting associates your Warp team with one or more GitHub App installations, enabling Oz cloud agents initiated with a [team API key](/reference/cli/api-keys/) to clone repositories and open pull requests using the Oz by Warp GitHub App. + +To configure: + +1. Navigate to the **Platform** section of the Admin Panel. +2. Under **Enabled GitHub Orgs**, review the list of GitHub organizations where the Oz by Warp GitHub App is installed. +3. Select which organizations your team should have access to. + +![Enabled GitHub Orgs setting in the Admin Panel Platform section](../../../../assets/agent-platform/admin-panel-enabled-github-orgs.png) + +The organizations and repository access shown here reflect the Oz by Warp GitHub App installation scope, which is configured in [GitHub settings](https://github.com/settings/installations). To change which repositories the app can access, edit the installation directly in GitHub. + +:::note +This setting controls GitHub access for team API key runs only. Runs triggered by individual users (via personal API key, Slack, or Linear) continue to use that user's personal GitHub token. For more details, see [Team GitHub authorization](/agent-platform/cloud-agents/team-access-billing-and-identity/#team-github-authorization). +::: + +## Multi-admin functionality + +Warp supports multiple team administrators to prevent single points of failure and enable distributed management. + +### Promoting and demoting admins + +Team admins can grant or revoke admin privileges: + +1. Navigate to **Settings** > **Teams** > **Team Members**. +2. Find the user you want to modify. +3. Click the role dropdown next to their name. +4. Select **Admin** or **Member**. +5. Click **Save**. + +:::note +We recommend at least one admin in addition to the Team Owner to prevent access issues if one is unavailable. The Team Owner has full access and can transfer ownership; Team Admins have the same permissions except they can't transfer ownership. +::: + +## Common admin workflows + +### Initial enterprise setup + +After purchasing a Warp enterprise plan: + +1. **Configure SSO** - Set up authentication with your identity provider. +2. **Enable Codebase Context** - Index your organization's repositories. +3. **Set agent autonomy** - Configure initial safety levels. +4. **Apply secret redaction** - Add custom patterns for your organization. +5. **Configure BYOLLM** (optional) - Route inference through your cloud accounts. +6. **Create shared resources** - Populate team Warp Drive with Workflows, Rules, and Prompts. + +See [Roles and permissions](/enterprise/team-management/roles-and-permissions/) for details on user roles and access controls. + +### Adjusting policies for different teams + +For organizations with multiple teams (e.g., DevOps, Data, Frontend): + +1. Create separate Warp teams for each group. +2. Assign team-specific admins. +3. Configure different autonomy levels per team. +4. Use directory allowlists to scope agent access to team repositories. + +### Responding to security incidents + +If an agent performs an unintended action: + +1. **Immediate:** Review agent action logs in the affected user's session. +2. **Short-term:** Add specific commands to the command denylist. +3. **Long-term:** Adjust autonomy settings to prevent similar incidents. +4. **Review:** Check the Admin Panel settings for the affected user's team to confirm what autonomy levels, allowlists, and restrictions were in effect. + +Warp logs all agent actions with full context, making incident investigation straightforward. + +## Troubleshooting + +### Users can't see new settings + +**Problem:** You changed a setting in the Admin Panel, but users report they don't see the change. + +**Solution:** +1. Verify the setting is not set to "Respect User Setting". +2. Ask users to restart Warp to force a settings refresh. +3. Confirm users are members of the correct team. +4. Check that users have logged in with SSO (not a personal account). + +### Setting is grayed out in Admin Panel + +**Problem:** A setting you want to configure appears grayed out or shows "Not available on your plan." + +**Solution:** +* This setting is restricted to higher-tier plans +* Review plan features at [warp.dev/pricing](https://www.warp.dev/pricing) +* Contact your account manager or [sales team](https://warp.dev/contact-sales) to upgrade + +### Command allowlist not working + +**Problem:** Agents still ask permission for commands that match your allowlist patterns. + +**Solution:** +1. Verify regex patterns are correct (test with a regex validator). +2. Check that commands don't also match the denylist (denylist takes precedence). +3. Confirm autonomy settings allow command execution. +4. Remember: Some commands are always restricted regardless of allowlist. + +## Support + +Enterprise customers have access to priority support: + +* **Dedicated channels** - Private Slack or Teams channels with Warp engineers +* **Account manager** - Direct contact for escalations and feature requests +* **Technical support** - Help with Admin Panel configuration and troubleshooting + +Reach out through your dedicated Slack/Teams channel or contact your account manager. diff --git a/src/content/docs/enterprise/team-management/roles-and-permissions.mdx b/src/content/docs/enterprise/team-management/roles-and-permissions.mdx new file mode 100644 index 0000000..df5bd07 --- /dev/null +++ b/src/content/docs/enterprise/team-management/roles-and-permissions.mdx @@ -0,0 +1,76 @@ +--- +title: Roles and permissions +description: >- + Understand user roles, permissions, and access controls for managing your + Warp Enterprise team. +--- + +Warp uses a role-based access model to control what team members can do within your organization. Admins manage team settings and enforce policies, while members use Warp's features within the boundaries admins define. + +## User roles + +Warp has three user roles: + +* **Team Owner** - Has full access to the Admin Panel and can manage team settings, invite users, assign roles, and transfer ownership of the team. There can only be one Owner. +* **Team Admin** - Same permissions as the Owner, except they can't transfer ownership of the team. +* **Member** - Standard access to Warp features and team resources. Members can use agents, access shared Warp Drive resources, and configure personal settings within the limits set by admins. + +## Managing admins + +Teams can have multiple admins. We recommend at least one admin in addition to the Team Owner to prevent access issues if one is unavailable. + +### Promoting or demoting admins + +1. Navigate to **Settings** > **Teams** > **Team Members**. +2. Find the user you want to modify. +3. Click the three-dot menu icon next to their name. +4. Select **Promote to Admin** or **Demote from Admin**. +5. Confirm the change when prompted. + +:::caution +Team Admins cannot demote or modify the Team Owner role. +::: + +## Permission details + +### What admins can do + +* **Team management** - View members, invite users, remove users, and assign roles. +* **Authentication** - Configure SSO and login requirements. +* **Agent policies** - Set autonomy levels, command allowlists/denylists, and directory access controls. +* **Security settings** - Configure secret redaction, telemetry controls, and data handling policies. +* **Feature controls** - Enable or disable Codebase Context, BYOLLM, sharing, and other features. +* **Billing** - Monitor credit usage, set spending limits, and manage subscriptions. + +### What members can do + +* **Use agents** - Run Oz agents locally and in the cloud within the policies admins define. +* **Access team resources** - Use shared Workflows, Notebooks, Prompts, Rules, and Environment Variables in Warp Drive. +* **Configure personal settings** - Adjust settings where admins have selected "Respect User Setting." +* **Share sessions** - Collaborate via session sharing (if enabled by admins). +* **Index codebases** - Trigger Codebase Context indexing for repositories (if enabled by admins). + +### Settings enforcement + +Admin-configured settings follow a three-tier model: + +* **Organization enforced** - Applies to all members. Users cannot override these settings. Use for security-critical policies (e.g., secret redaction, command denylists). +* **Respect user setting** - Admins set a default, but individual users can customize. Use for preferences that don't impact security. +* **Tier restricted** - Setting is locked based on billing plan and cannot be changed until the plan is upgraded. + +See the [Admin Panel](/enterprise/team-management/admin-panel/) documentation for details on configuring each setting. + +## Resource sharing controls + +Admins control how team members collaborate and share Warp Drive resources: + +* **Direct link sharing** - Allow team members to share Notebooks, Workflows, Prompts, and other objects via direct links. +* **Team-only links** - Restrict links so only team members can access them. +* **Public link sharing** - Enable or disable access for anyone with the link (even non-team members). + +For organizations with sensitive internal processes, disable public link sharing to prevent accidental exposure. + +## Related resources + +* [Admin Panel](/enterprise/team-management/admin-panel/) - Configure team settings and enforce policies +* [Getting started for developers](/enterprise/getting-started/getting-started-developers/) - Developer onboarding guide diff --git a/src/content/docs/enterprise/team-management/teams.mdx b/src/content/docs/enterprise/team-management/teams.mdx new file mode 100644 index 0000000..21a749b --- /dev/null +++ b/src/content/docs/enterprise/team-management/teams.mdx @@ -0,0 +1,140 @@ +--- +title: Teams +description: >- + Create and manage teams in Warp to organize users, share resources, and + collaborate across your engineering organization. +--- + +## What is a team? + +A team is a group of Warp users who collaborate together. Teams share a dedicated workspace in [Warp Drive](/knowledge-and-collaboration/warp-drive/), giving members access to shared Workflows, Notebooks, Prompts, Rules, Plans, and Environment Variables. + +Teams are the foundation of Warp's enterprise experience — they enable centralized administration, shared configuration, and team-wide policy enforcement through the [Admin Panel](/enterprise/team-management/admin-panel/). + +:::note +Each Warp user can be an admin or member of one team at a time. +::: + +## Creating a team + +You can create a new team in two ways: + +{/* TODO: Add screenshots for both team creation entry points */} +* From the **Warp Drive** side panel, click **+ Create a team**. +* In Warp, navigate to **Settings** > **Teams** and follow the prompts. + +When creating a team, give it a meaningful name that represents your organization, company, or project. The person who creates the team becomes the **Team Owner**. + +:::note +You can rename your team at any time by going to **Settings** > **Teams**, clicking on the team name, entering the new name, and pressing `Enter`. +::: + +### Inviting team members + +Under **Settings** > **Teams**, copy the invite link and share it with your teammates through a secure channel like Slack or email. + +:::caution +On paid plans, adding new members automatically adds them as paid seats. New members are billed on a prorated basis for the remainder of the billing cycle. See [Billing](/enterprise/support-and-resources/billing/) for details. +::: + +## Restricting team invites by domain + +Team Admins can restrict team membership to users with specific email domains — for example, your company's email domain. + +To enable domain restriction: + +1. Navigate to **Settings** > **Teams**. +2. Toggle on **Restrict by domain**. +3. Add your allowed email domains to the allowlist. + +When domain restriction is enabled, users who attempt to join with a non-matching email domain will be prompted to authenticate via an emailed link sent to an email address on an allowed domain. + +## Joining a team + +If you've received an invite link, use it to sign up or log in and join the team. If the team uses domain restriction, you'll need to verify that you have access to an email address on an allowed domain before joining. + +## Leaving and deleting teams + +* **Members and Admins** - Can leave a team at any time by visiting **Settings** > **Teams** and clicking **Leave team**. +* **Team Owners** - Can delete a team, but only after removing all other team members first. + +:::caution +If you're a Team Owner and choose to [delete your Warp account](/support-and-community/privacy-and-security/privacy/#delete-your-account-and-data), you'll need to assign a team member as the new owner before your account can be deleted. +::: + +## Team discoverability + +Team admins can make their team discoverable to colleagues who share the same email domain. When enabled, new users with a matching domain can find and join the team without needing a direct invite link. + +To enable discoverability, go to **Settings** > **Teams** > **Make team discoverable**. + +:::note +While discoverability is enabled, any new user who joins the team will add a prorated charge to the team's next billing cycle. +::: + +## Transferring team ownership + +Team Owners can transfer ownership to another team member: + +{/* TODO: Add screenshot of transfer ownership flow */} +1. Navigate to **Settings** > **Teams** > **Team Members**. +2. Click the three-dot menu icon next to the member you want to transfer ownership to. +3. Click **Transfer ownership**. + +Only the current Team Owner can initiate an ownership transfer. After the transfer, the previous owner becomes a regular member (or admin, depending on the team's configuration). + +:::note +If the new owner's email is not on a work domain, team discoverability will be automatically disabled as a safety measure. +::: + +## Team roles and permissions + +Warp uses three roles to manage team access: + +* **Team Owner** - Full access to the Admin Panel and all team settings. Can manage members, assign roles, configure policies, and transfer ownership. There can only be one Owner per team. +* **Team Admin** - Same permissions as the Owner, except they cannot transfer team ownership. Teams on Enterprise plans can have multiple admins. +* **Member** - Standard access to Warp features and team resources. Members can use agents, access shared Warp Drive resources, and configure personal settings within the limits set by admins. + +:::note +We recommend having at least one Team Admin in addition to the Team Owner to prevent access issues if one is unavailable. +::: + +### Permissions overview + +| | Owner | Admin | Member | +| --- | --- | --- | --- | +|| Create a team | ✓ | ✓ | ✓ | +| Restrict invites by domain | ✓ | ✓ | | +| Invite members | ✓ | ✓ | ✓ | +| Remove team members | ✓ | ✓ | | +|| Leave a team | | ✓ | ✓ | +| Delete a team | ✓ | | | +| Transfer ownership | ✓ | | | +| Promote/demote admins | ✓ | ✓ | | +| Manage billing | ✓ | ✓ | | +| Configure Admin Panel settings | ✓ | ✓ | | + +### Multi-admin support + +Teams on the **Enterprise** plan can have multiple admins, enabling distributed management and preventing single points of failure. + +To promote or demote a team admin: + +{/* TODO: Add screenshot of promote/demote admin flow */} +1. Navigate to **Settings** > **Teams** > **Team Members**. +2. Find the user you want to modify and click the three-dot menu icon next to their name. +3. Click **Promote to Admin** or **Demote from Admin**. +4. Confirm the change when prompted. + +:::caution +Team Admins cannot demote or modify the Team Owner's role. The Owner role can only change through an ownership transfer. +::: + +For detailed information on what each role can do and how settings enforcement works, see [Roles and permissions](/enterprise/team-management/roles-and-permissions/). + +## Related resources + +* [Admin Panel](/enterprise/team-management/admin-panel/) - Configure team settings and enforce policies +* [Roles and permissions](/enterprise/team-management/roles-and-permissions/) - Detailed permission breakdowns and settings enforcement +* [Getting started for admins](/enterprise/getting-started/getting-started-enterprise/) - Admin onboarding guide +* [Billing](/enterprise/support-and-resources/billing/) - Understand team billing and seat management diff --git a/src/content/docs/getting-started/keyboard-shortcuts.mdx b/src/content/docs/getting-started/keyboard-shortcuts.mdx new file mode 100644 index 0000000..7a3bb91 --- /dev/null +++ b/src/content/docs/getting-started/keyboard-shortcuts.mdx @@ -0,0 +1,512 @@ +--- +title: Keyboard Shortcuts +description: >- + View, customize, and remap keyboard shortcuts for all Warp features. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +Warp opens with a shortcut screen showing some of the most commonly used keyboard shortcuts. Hide the shortcut screen by clicking the x button. Quickly view keyboard shortcuts via the [Command Palette](/terminal/command-palette/) or the Resource Center keyboard shortcut sidebar. + +## Custom keyboard shortcuts + +Set custom, clear, or default keyboard shortcuts by navigating to **Settings** > **Keyboard shortcuts**. Search through the re-mappable actions or existing shortcuts using the search bar. + +Remap the keyboard shortcuts using a file. See our [keysets repository](https://github.com/warpdotdev/keysets/tree/main) for instructions. + +:::note +On macOS, [system keyboard shortcuts](https://support.apple.com/en-us/HT201236) like `CMD-ESC`, `CMD-BACKTICK`, `CMD-TAB`, `CMD-PERIOD`, and `CMD-TILDE` need to be [unbound](https://support.apple.com/guide/mac-help/keyboard-shortcuts-mchlp2262/mac) before you can use them in Warp. +::: + +:::caution +Keybinds that conflict with others are highlighted with an orange border. +::: + +![keybinds that conflict with others are highlighted in orange](../../../assets/terminal/keybinds-conflict.png) + +## All available shortcuts + +<Tabs> + <TabItem label="macOS"> + **Warp Essentials** + + | Shortcut | Command | Action | + | -------------- | ---------------------------- | ---------------------------------------------- | + | `CMD-D` | Split Pane Right | `pane_group:add_right` | + | `CTRL-CMD-L` | Launch Configuration Palette | `workspace:toggle_launch_config_palette` | + | `CTRL-CMD-T` | Open Theme Picker | `workspace:show_theme_chooser` | + | `CTRL-R` | Command Search | `workspace:show_command_search` | + | `CTRL-SHIFT-R` | Workflows | `input:toggle_workflows` | + | `` CTRL-` `` | Generate | `input:toggle_natural_language_command_search` | + | `CMD-L` | Focus Terminal Input | `terminal:focus_input` | + | `CTRL-I` | Warpify Subshell | `terminal:trigger_subshell_bootstrap` | + | `CMD-\` | Warp Drive | `terminal:toggle_warp_drive` | + | `CMD-O` | File search | | + | `CMD-P` | Open Command Palette | + + **Blocks** + + | Shortcut | Command | Action | + | ----------------- | --------------------------------- | ------------------------------------------------------ | + | `ALT-DOWN` | Select the Closest Bookmark Down | `terminal:select_bookmark_down` | + | `ALT-SHIFT-CMD-C` | Copy Command Output | `terminal:copy_outputs` | + | `ALT-UP` | Select the Closest Bookmark Up | `terminal:select_bookmark_up` | + | `CMD-A` | Select All Blocks | `terminal:select_all_blocks` | + | `CMD-K` | Clear Blocks | `terminal:clear_blocks` | + | `CMD-B` | Bookmark Selected Block | `terminal:bookmark_selected_block` | + | `CMD-DOWN` | Select Next Block | `terminal:select_next_block` | + | `CMD-I` | Reinput Selected Commands | `terminal:reinput_commands` | + | `CMD-UP` | Select Previous Block | `terminal:select_previous_block` | + | `CTRL-M` | Open Block Context Menu | `terminal:open_block_list_context_menu_via_keybinding` | + | `SHIFT-CMD-C` | Copy Command | `terminal:copy_commands` | + | `SHIFT-CMD-I` | Reinput Selected Commands as Root | `terminal:reinput_commands_with_sudo` | + | `SHIFT-CMD-S` | Share Selected Block | `terminal:open_share_modal` | + | `SHIFT-DOWN` | Expand Selected Blocks Below | `terminal:expand_block_selection_below` | + | `SHIFT-UP` | Expand Selected Blocks Above | `terminal:expand_block_selection_above` | + + **Scrolling** + + | Shortcut | Command | Action | + | ---------------- | -------------------------------------------- | --------------------------------------------------------- | + | `PAGE UP` | Scroll Up One Page | `terminal:page_up` | + | `PAGE DOWN` | Scroll Down One Page | `terminal:page_down` | + | `HOME` | Scroll to Top | `terminal:home` | + | `END` | Scroll to Bottom | `terminal:end` | + | `SHIFT-CMD-UP` | Scroll to Top of Selected Block | `terminal:scroll_to_top_of_selected_block` | + | `SHIFT-CMD-DOWN` | Scroll to Bottom of Selected Block | `terminal:scroll_to_bottom_of_selected_block` | + | | Scroll Terminal Output Up One Line | `terminal:scroll_up_one_line` | + | | Scroll Terminal Output Down One Line | `terminal:scroll_down_one_line` | + + :::note + "Scroll Terminal Output Up/Down One Line" has no default keybinding. You can assign one in Settings > Keyboard shortcuts or trigger it from the [Command Palette](/terminal/command-palette/). During long-running or full-screen commands, `PAGE UP`, `PAGE DOWN`, `HOME`, and `END` are forwarded to the running program. + ::: + + **Input Editor** + + | Shortcut | Command | Action | + | ----------------- | ----------------------------------------- | ------------------------------------------ | + | `ALT-BACKSPACE` | Delete Word Left | `editor:delete_word_left` | + | `ALT-CMD-F` | Fold Selected Ranges | `editor_view:fold_selected_ranges` | + | `ALT-CMD-[` | Fold | `editor_view:fold` | + | `ALT-CMD-]` | Unfold | `editor_view:unfold` | + | `ALT-DELETE` | Delete Word Right | `editor:delete_word_right` | + | `CMD-A` | Select All | `editor_view:select_all` | + | `CMD-BACKSPACE` | Delete All Left | `editor_view:delete_all_left` | + | `CMD-DELETE` | Delete All Right | `editor_view:delete_all_right` | + | `CMD-DOWN` | Move Cursor to the Bottom | `editor_view:cmd_down` | + | `CMD-I` | Inspect Command | `editor_view:cmd_i` | + | `CMD-LEFT` | Home | `editor_view:home` | + | `CMD-RIGHT` | End | `editor_view:end` | + | `CTRL-A` | Move to Start of Line | `editor_view:move_to_line_start` | + | `CTRL-B` | Move Cursor Left | `editor_view:left` | + | `CTRL-C` | Clear Command Editor | `editor_view:clear_buffer` | + | `CTRL-D` | Delete | `editor_view:delete` | + | `CTRL-E` | Move to End of Line | `editor_view:move_to_line_end` | + | `CTRL-F` | Move Cursor Right / Accept Autosuggestion | `editor_view:right` | + | `CTRL-G` | Add Selection for Next Occurrence | `editor_view:add_next_occurrence` | + | `CTRL-H` | Remove the Previous Character | `editor_view:backspace` | + | `CTRL-J` | Insert Newline | `editor_view:insert_newline` | + | `CTRL-K` | Cut All Right | `editor_view:cut_all_right` | + | `CTRL-L` | Clear Screen | `input:clear_screen` | + | `CTRL-N` | Move Cursor Down | `editor_view:down` | + | `CTRL-P` | Move Cursor Up | `editor_view:up` | + | `CTRL-SHIFT-A` | Select to Start of Line | `editor_view:select_to_line_start` | + | `CTRL-SHIFT-B` | Select One Character to the Left | `editor_view:select_left` | + | `CTRL-SHIFT-DOWN` | Add Cursor Below | `editor_view:add_cursor_below` | + | `CTRL-SHIFT-E` | Select to End of Line | `editor:select_to_line_end` | + | `CMD-Z` | Undo | `editor:undo` | + | `CMD-SHIFT-Z` | Redo | `editor:redo` | + | `CTRL-SHIFT-F` | Select One Character to the Right | `editor:select_right` | + | `CTRL-SHIFT-N` | Select Down | `editor_view:select_down` | + | `CTRL-SHIFT-P` | Select Up | `editor_view:select_up` | + | `CTRL-SHIFT-UP` | Add Cursor Above | `editor_view:add_cursor_above` | + | `CTRL-U` | Copy and Clear Selected Lines | `editor_view:clear_and_copy_lines` | + | `CTRL-W` | Cut Word Left | `editor_view:cut_word_left` | + | `META-.` | Insert Last Word of Previous Command | `editor:insert_last_word_previous_command` | + | `META-A` | Move to the Start of the Paragraph | `editor_view:move_to_paragraph_start` | + | `META-B` | Move Backward One Word | `editor_view:move_backward_one_word` | + | `META-D` | Cut Word Right | `editor_view:cut_word_right` | + | `META-E` | Move to the End of the Paragraph | `editor_view:move_to_paragraph_end` | + | `META-F` | Move Forward One Word | `editor_view:move_forward_one_word` | + | `CTRL-OPT-LEFT` | Move Backward One Subword | `editor_view:move_backward_one_subword` | + | `CTRL-OPT-RIGHT` | Move Forward One Subword | `editor_view:move_forward_one_subword` | + | `SHIFT-CMD-K` | Clear Selected Lines | `editor_view:clear_lines` | + | `SHIFT-META-<` | Move to the Start of the Buffer | `editor_view:move_to_buffer_start` | + | `SHIFT-META->` | Move to the End of the Buffer | `editor_view:move_to_buffer_end` | + | `SHIFT-META-B` | Select One Word to the Left | `editor_view:select_left_by_word` | + | `SHIFT-META-F` | Select One Word to the Right | `editor_view:select_right_by_word` | + + **Terminal** + + | Shortcut | Command | Action | + | ----------------- | ------------------------------------------------- | -------------------------------------------- | + | `ALT-CMD-DOWN` | Switch Panes Down | `pane_group:navigate_down` | + | `ALT-CMD-LEFT` | Switch Panes Left | `pane_group:navigate_left` | + | `ALT-CMD-RIGHT` | Switch Panes Right | `pane_group:navigate_right` | + | `ALT-CMD-UP` | Switch Panes Up | `pane_group:navigate_up` | + | `ALT-CMD-V` | \[a11y] Set Concise Accessibility Announcements | `workspace:set_a11y_concise_verbosity_level` | + | `ALT-CMD-V` | \[a11y] Set Verbose Accessibility Announcements | `workspace:set_a11y_verbose_verbosity_level` | + | `CMD-,` | Open Settings | `workspace:show_settings_modal` | + | `CMD-,` | Open Settings: Account | `workspace:show_settings_account_page` | + | `CMD-G` | Find the Next Occurrence of Your Search Query | `find:find_next_occurrence` | + | `CMD-P` | Toggle Command Palette | `workspace:toggle_command_palette` | + | | Toggle Mouse Reporting | `workspace:toggle_mouse_reporting` | + | `CMD-[` | Activate Previous Pane | `pane_group:navigate_prev` | + | `CMD-]` | Activate Next Pane | `pane_group:navigate_next` | + | `CTRL-CMD-DOWN` | Resize Pane > Move Divider Down | `pane_group:resize_down` | + | `CTRL-CMD-K` | Open Keybindings Editor | `workspace:show_keybinding_settings` | + | `CTRL-CMD-LEFT` | Resize Pane > Move Divider Left | `pane_group:resize_left` | + | `CTRL-CMD-RIGHT` | Resize Pane > Move Divider Right | `pane_group:resize_right` | + | `CTRL-CMD-UP` | Resize Pane > Move Divider Up | `pane_group:resize_up` | + | `CTRL-SHIFT-?` | Open Resource Center | `workspace:toggle_resource_center` | + | `SHIFT-CMD-D` | Split Pane Down | `pane_group:add_down` | + | `SHIFT-CMD-ENTER` | Toggle Maximize Active Pane | `pane_group:toggle_maximize_pane` | + | `SHIFT-CMD-G` | Find the Previous Occurrence of Your Search Query | `find:find_prev_occurrence` | + | `SHIFT-CMD-P` | Toggle Navigation Palette | `workspace:toggle_navigation_palette` | + + **Fundamentals** + + | Shortcut | Command | Action | + | ------------------ | -------------------------- | -------------------------------- | + | `CMD--` | Decrease Font Size | `workspace:decrease_font_size` | + | `CMD-0` | Reset Font Size to Default | `workspace:reset_font_size` | + | `CMD-1` | Switch to 1st Tab | `workspace:activate_first_tab` | + | `CMD-2` | Switch to 2nd Tab | `workspace:activate_second_tab` | + | `CMD-3` | Switch to 3rd Tab | `workspace:activate_third_tab` | + | `CMD-4` | Switch to 4th Tab | `workspace:activate_fourth_tab` | + | `CMD-5` | Switch to 5th Tab | `workspace:activate_fifth_tab` | + | `CMD-6` | Switch to 6th Tab | `workspace:activate_sixth_tab` | + | `CMD-7` | Switch to 7th Tab | `workspace:activate_seventh_tab` | + | `CMD-8` | Switch to 8th Tab | `workspace:activate_eighth_tab` | + | `CMD-9` | Switch to Last Tab | `workspace:activate_last_tab` | + | `CMD-=` | Increase Font Size | `workspace:increase_font_size` | + | `CMD-C` | Copy | `terminal:copy` | + | `CMD-F` | Find | `terminal:find` | + | `CMD-V` | Paste | `terminal:paste` | + | `CMD-T` | Open New Tab | `workspace:open_new_tab` | + | `SHIFT-CMD-T` | Reopen Closed Tab | `workspace:reopen_closed_tab` | + | `CTRL-SHIFT-LEFT` | Move Tab Left | `workspace:move_tab_left` | + | `CTRL-SHIFT-RIGHT` | Move Tab Right | `workspace:move_tab_right` | + | `SHIFT-CMD-{` | Activate Previous Tab | `workspace:activate_prev_tab` | + | `SHIFT-CMD-}` | Activate Next Tab | `workspace:activate_next_tab` | + </TabItem> + <TabItem label="Windows"> + **Warp Essentials** + + | Shortcut | Command | Action | + | -------------- | ---------------------------- | ---------------------------------------------- | + | `CTRL-SHIFT-D` | Split Pane Right | `pane_group:add_right` | + | | Launch Configuration Palette | `workspace:toggle_launch_config_palette` | + | | Open Theme Picker | `workspace:show_theme_chooser` | + | `CTRL-R` | Command Search | `workspace:show_command_search` | + | `CTRL-SHIFT-R` | Workflows | `input:toggle_workflows` | + | `` CTRL-` `` | Generate | `input:toggle_natural_language_command_search` | + | `CTRL-SHIFT-L` | Focus Terminal Input | `terminal:focus_input` | + | `CTRL-I` | Warpify Subshell | `terminal:trigger_subshell_bootstrap` | + | `CTRL-SHIFT-\` | Warp Drive | `terminal:toggle_warp_drive` | + + **Blocks** + + | Shortcut | Command | Action | + | ------------------ | --------------------------------- | ------------------------------------------------------ | + | `ALT-DOWN` | Select the Closest Bookmark Down | `terminal:select_bookmark_down` | + | `CTRL-SHIFT-ALT-C` | Copy Command Output | `terminal:copy_outputs` | + | `ALT-UP` | Select the Closest Bookmark Up | `terminal:select_bookmark_up` | + | `CTRL-SHIFT-A` | Select All Blocks | `terminal:select_all_blocks` | + | `CTRL-SHIFT-K` | Clear Blocks | `terminal:clear_blocks` | + | `CTRL-SHIFT-B` | Bookmark Selected Block | `terminal:bookmark_selected_block` | + | `CTRL-DOWN` | Select Next Block | `terminal:select_next_block` | + | `CTRL-SHIFT-I` | Reinput Selected Commands | `terminal:reinput_commands` | + | `CTRL-UP` | Select Previous Block | `terminal:select_previous_block` | + | | Open Block Context Menu | `terminal:open_block_list_context_menu_via_keybinding` | + | `CTRL-SHIFT-C` | Copy Command | `terminal:copy_commands` | + | | Reinput Selected Commands as Root | `terminal:reinput_commands_with_sudo` | + | `CTRL-SHIFT-S` | Share Selected Block | `terminal:open_share_modal` | + | `SHIFT-DOWN` | Expand Selected Blocks Below | `terminal:expand_block_selection_below` | + | `SHIFT-UP` | Expand Selected Blocks Above | `terminal:expand_block_selection_above` | + + **Scrolling** + + | Shortcut | Command | Action | + | ------------------ | -------------------------------------------- | --------------------------------------------------------- | + | `PAGE UP` | Scroll Up One Page | `terminal:page_up` | + | `PAGE DOWN` | Scroll Down One Page | `terminal:page_down` | + | `HOME` | Scroll to Top | `terminal:home` | + | `END` | Scroll to Bottom | `terminal:end` | + | `CTRL-SHIFT-UP` | Scroll to Top of Selected Block | `terminal:scroll_to_top_of_selected_block` | + | `CTRL-SHIFT-DOWN` | Scroll to Bottom of Selected Block | `terminal:scroll_to_bottom_of_selected_block` | + | | Scroll Terminal Output Up One Line | `terminal:scroll_up_one_line` | + | | Scroll Terminal Output Down One Line | `terminal:scroll_down_one_line` | + + :::note + "Scroll Terminal Output Up/Down One Line" has no default keybinding. You can assign one in Settings > Keyboard shortcuts or trigger it from the [Command Palette](/terminal/command-palette/). During long-running or full-screen commands, `PAGE UP`, `PAGE DOWN`, `HOME`, and `END` are forwarded to the running program. + ::: + + **Input Editor** + + | Shortcut | Command | Action | + | ------------------ | ----------------------------------------- | ------------------------------------------ | + | `CTRL-BACKSPACE` | Delete Word Left | `editor:delete_word_left` | + | `CTRL-ALT-F` | Fold Selected Ranges | `editor_view:fold_selected_ranges` | + | `CTRL-ALT-[` | Fold | `editor_view:fold` | + | `CTRL-ALT-]` | Unfold | `editor_view:unfold` | + | `CTRL-DELETE` | Delete Word Right | `editor:delete_word_right` | + | `CTRL-A` | Select All | `editor_view:select_all` | + | `CTRL-Y` | Delete All Left | `editor_view:delete_all_left` | + | | Delete All Right | `editor_view:delete_all_right` | + | `CTRL-END` | Move Cursor to the Bottom | `editor_view:cmd_down` | + | `CTRL-I` | Inspect Command | `editor_view:cmd_i` | + | `HOME` | Home | `editor_view:home` | + | `END` | End | `editor_view:end` | + | `CTRL-A` | Move to Start of Line | `editor_view:move_to_line_start` | + | `CTRL-B` | Move Cursor Left | `editor_view:left` | + | `CTRL-C` | Clear Command Editor | `editor_view:clear_buffer` | + | `CTRL-D` | Delete | `editor_view:delete` | + | `CTRL-E` | Move to End of Line | `editor_view:move_to_line_end` | + | `CTRL-F` | Move Cursor Right / Accept Autosuggestion | `editor_view:right` | + | `CTRL-G` | Add Selection for Next Occurrence | `editor_view:add_next_occurrence` | + | `CTRL-H` | Remove the Previous Character | `editor_view:backspace` | + | `CTRL-J` | Insert Newline | `editor_view:insert_newline` | + | `CTRL-K` | Cut All Right | `editor_view:cut_all_right` | + | `CTRL-L` | Clear Screen | `input:clear_screen` | + | `CTRL-N` | Move Cursor Down | `editor_view:down` | + | `CTRL-P` | Move Cursor Up | `editor_view:up` | + | | Select to Start of Line | `editor_view:select_to_line_start` | + | `CTRL-SHIFT-B` | Select One Character to the Left | `editor_view:select_left` | + | `CTRL-SHIFT-DOWN` | Add Cursor Below | `editor_view:add_cursor_below` | + | | Select to End of Line | `editor:select_to_line_end` | + | `CTRL-Z` | Undo | `editor:undo` | + | `CTRL-SHIFT-Z` | Redo | `editor:redo` | + | `CTRL-SHIFT-F` | Select One Character to the Right | `editor:select_right` | + | | Select Down | `editor_view:select_down` | + | `CTRL-SHIFT-P` | Select Up | `editor_view:select_up` | + | `CTRL-SHIFT-UP` | Add Cursor Above | `editor_view:add_cursor_above` | + | `CTRL-U` | Copy and Clear Selected Lines | `editor_view:clear_and_copy_lines` | + | `CTRL-W` | Cut Word Left | `editor_view:cut_word_left` | + | `META-.` | Insert Last Word of Previous Command | `editor:insert_last_word_previous_command` | + | `META-A` | Move to the Start of the Paragraph | `editor_view:move_to_paragraph_start` | + | `CTRL-LEFT` | Move Backward One Word | `editor_view:move_backward_one_word` | + | `ALT-D` | Cut Word Right | `editor_view:cut_word_right` | + | `META-E` | Move to the End of the Paragraph | `editor_view:move_to_paragraph_end` | + | `CTRL-RIGHT` | Move Forward One Word | `editor_view:move_forward_one_word` | + | `CTRL-ALT-LEFT` | Move Backward One Subword | `editor_view:move_backward_one_subword` | + | `CTRL-ALT-RIGHT` | Move Forward One Subword | `editor_view:move_forward_one_subword` | + | `SHIFT-META-<` | Move to the Start of the Buffer | `editor_view:move_to_buffer_start` | + | `SHIFT-META->` | Move to the End of the Buffer | `editor_view:move_to_buffer_end` | + | `CTRL-SHIFT-LEFT` | Select One Word to the Left | `editor_view:select_left_by_word` | + | `CTRL-SHIFT-RIGHT` | Select One Word to the Right | `editor_view:select_right_by_word` | + + **Terminal** + + | Shortcut | Command | Action | + | ------------------ | ------------------------------------------------- | -------------------------------------------- | + | `CTRL-ALT-DOWN` | Switch Panes Down | `pane_group:navigate_down` | + | `CTRL-ALT-LEFT` | Switch Panes Left | `pane_group:navigate_left` | + | `CTRL-ALT-RIGHT` | Switch Panes Right | `pane_group:navigate_right` | + | `CTRL-ALT-UP` | Switch Panes Up | `pane_group:navigate_up` | + | `CTRL-ALT-V` | \[a11y] Set Concise Accessibility Announcements | `workspace:set_a11y_concise_verbosity_level` | + | `CTRL-ALT-V` | \[a11y] Set Verbose Accessibility Announcements | `workspace:set_a11y_verbose_verbosity_level` | + | `CTRL-,` | Open Settings | `workspace:show_settings_modal` | + | `CTRL-,` | Open Settings: Account | `workspace:show_settings_account_page` | + | `F3` | Find the Next Occurrence of Your Search Query | `find:find_next_occurrence` | + | `CTRL-SHIFT-P` | Toggle Command Palette | `workspace:toggle_command_palette` | + | | Toggle Mouse Reporting | `workspace:toggle_mouse_reporting` | + | `CTRL-SHIFT-[` | Activate Previous Pane | `pane_group:navigate_prev` | + | `CTRL-SHIFT-]` | Activate Next Pane | `pane_group:navigate_next` | + | | Resize Pane > Move Divider Down | `pane_group:resize_down` | + | `CTRL-CMD-K` | Open Keybindings Editor | `workspace:show_keybinding_settings` | + | | Resize Pane > Move Divider Left | `pane_group:resize_left` | + | | Resize Pane > Move Divider Right | `pane_group:resize_right` | + | | Resize Pane > Move Divider Up | `pane_group:resize_up` | + | `CTRL-SHIFT-/` | Open Resource Center | `workspace:toggle_resource_center` | + | `CTRL-SHIFT-E` | Split Pane Down | `pane_group:add_down` | + | `CTRL-SHIFT-ENTER` | Toggle Maximize Active Pane | `pane_group:toggle_maximize_pane` | + | `SHIFT-F3` | Find the Previous Occurrence of Your Search Query | `find:find_prev_occurrence` | + | | Toggle Navigation Palette | `workspace:toggle_navigation_palette` | + + **Fundamentals** + + | Shortcut | Command | Action | + | ------------------ | -------------------------- | -------------------------------- | + | `CTRL--` | Decrease Font Size | `workspace:decrease_font_size` | + | `CTRL-0` | Reset Font Size to Default | `workspace:reset_font_size` | + | `CTRL-1` | Switch to 1st Tab | `workspace:activate_first_tab` | + | `CTRL-2` | Switch to 2nd Tab | `workspace:activate_second_tab` | + | `CTRL-3` | Switch to 3rd Tab | `workspace:activate_third_tab` | + | `CTRL-4` | Switch to 4th Tab | `workspace:activate_fourth_tab` | + | `CTRL-5` | Switch to 5th Tab | `workspace:activate_fifth_tab` | + | `CTRL-6` | Switch to 6th Tab | `workspace:activate_sixth_tab` | + | `CTRL-7` | Switch to 7th Tab | `workspace:activate_seventh_tab` | + | `CTRL-8` | Switch to 8th Tab | `workspace:activate_eighth_tab` | + | `CTRL-9` | Switch to Last Tab | `workspace:activate_last_tab` | + | `CTRL-=` | Increase Font Size | `workspace:increase_font_size` | + | `CTRL-SHIFT-C` | Copy | `terminal:copy` | + | `CTRL-SHIFT-F` | Find | `terminal:find` | + | `CTRL-SHIFT-V` | Paste | `terminal:paste` | + | `CTRL-SHIFT-T` | Open New Tab | `workspace:open_new_tab` | + | `CTRL-ALT-T` | Reopen Closed Tab | `workspace:reopen_closed_tab` | + | `CTRL-SHIFT-LEFT` | Move Tab Left | `workspace:move_tab_left` | + | `CTRL-SHIFT-RIGHT` | Move Tab Right | `workspace:move_tab_right` | + | `CTRL-PAGEUP` | Activate Previous Tab | `workspace:activate_prev_tab` | + | `CTRL-PAGEDOWN` | Activate Next Tab | `workspace:activate_next_tab` | + </TabItem> + <TabItem label="Linux"> + **Warp Essentials** + + | Shortcut | Command | Action | + | -------------- | ---------------------------- | ---------------------------------------------- | + | `CTRL-SHIFT-D` | Split Pane Right | `pane_group:add_right` | + | | Launch Configuration Palette | `workspace:toggle_launch_config_palette` | + | | Open Theme Picker | `workspace:show_theme_chooser` | + | `CTRL-R` | Command Search | `workspace:show_command_search` | + | `CTRL-SHIFT-R` | Workflows | `input:toggle_workflows` | + | `` CTRL-` `` | Generate | `input:toggle_natural_language_command_search` | + | `CTRL-SHIFT-L` | Focus Terminal Input | `terminal:focus_input` | + | `CTRL-I` | Warpify Subshell | `terminal:trigger_subshell_bootstrap` | + | `CTRL-SHIFT-\` | Warp Drive | `terminal:toggle_warp_drive` | + + **Blocks** + + | Shortcut | Command | Action | + | ------------------ | --------------------------------- | ------------------------------------------------------ | + | `ALT-DOWN` | Select the Closest Bookmark Down | `terminal:select_bookmark_down` | + | `CTRL-SHIFT-ALT-C` | Copy Command Output | `terminal:copy_outputs` | + | `ALT-UP` | Select the Closest Bookmark Up | `terminal:select_bookmark_up` | + | `CTRL-SHIFT-A` | Select All Blocks | `terminal:select_all_blocks` | + | `CTRL-SHIFT-K` | Clear Blocks | `terminal:clear_blocks` | + | `CTRL-SHIFT-B` | Bookmark Selected Block | `terminal:bookmark_selected_block` | + | `CTRL-DOWN` | Select Next Block | `terminal:select_next_block` | + | `CTRL-SHIFT-I` | Reinput Selected Commands | `terminal:reinput_commands` | + | `CTRL-UP` | Select Previous Block | `terminal:select_previous_block` | + | | Open Block Context Menu | `terminal:open_block_list_context_menu_via_keybinding` | + | `CTRL-SHIFT-C` | Copy Command | `terminal:copy_commands` | + | | Reinput Selected Commands as Root | `terminal:reinput_commands_with_sudo` | + | `CTRL-SHIFT-S` | Share Selected Block | `terminal:open_share_modal` | + | `SHIFT-DOWN` | Expand Selected Blocks Below | `terminal:expand_block_selection_below` | + | `SHIFT-UP` | Expand Selected Blocks Above | `terminal:expand_block_selection_above` | + + **Scrolling** + + | Shortcut | Command | Action | + | ------------------ | -------------------------------------------- | --------------------------------------------------------- | + | `PAGE UP` | Scroll Up One Page | `terminal:page_up` | + | `PAGE DOWN` | Scroll Down One Page | `terminal:page_down` | + | `HOME` | Scroll to Top | `terminal:home` | + | `END` | Scroll to Bottom | `terminal:end` | + | `CTRL-SHIFT-UP` | Scroll to Top of Selected Block | `terminal:scroll_to_top_of_selected_block` | + | `CTRL-SHIFT-DOWN` | Scroll to Bottom of Selected Block | `terminal:scroll_to_bottom_of_selected_block` | + | | Scroll Terminal Output Up One Line | `terminal:scroll_up_one_line` | + | | Scroll Terminal Output Down One Line | `terminal:scroll_down_one_line` | + + :::note + "Scroll Terminal Output Up/Down One Line" has no default keybinding. You can assign one in Settings > Keyboard shortcuts or trigger it from the [Command Palette](/terminal/command-palette/). During long-running or full-screen commands, `PAGE UP`, `PAGE DOWN`, `HOME`, and `END` are forwarded to the running program. + ::: + + **Input Editor** + + | Shortcut | Command | Action | + | ------------------ | ----------------------------------------- | ------------------------------------------ | + | `CTRL-BACKSPACE` | Delete Word Left | `editor:delete_word_left` | + | `CTRL-ALT-F` | Fold Selected Ranges | `editor_view:fold_selected_ranges` | + | `CTRL-ALT-[` | Fold | `editor_view:fold` | + | `CTRL-ALT-]` | Unfold | `editor_view:unfold` | + | `CTRL-DELETE` | Delete Word Right | `editor:delete_word_right` | + | `CTRL-A` | Select All | `editor_view:select_all` | + | `CTRL-Y` | Delete All Left | `editor_view:delete_all_left` | + | | Delete All Right | `editor_view:delete_all_right` | + | `CTRL-END` | Move Cursor to the Bottom | `editor_view:cmd_down` | + | `CTRL-I` | Inspect Command | `editor_view:cmd_i` | + | `HOME` | Home | `editor_view:home` | + | `END` | End | `editor_view:end` | + | `CTRL-A` | Move to Start of Line | `editor_view:move_to_line_start` | + | `CTRL-B` | Move Cursor Left | `editor_view:left` | + | `CTRL-C` | Clear Command Editor | `editor_view:clear_buffer` | + | `CTRL-D` | Delete | `editor_view:delete` | + | `CTRL-E` | Move to End of Line | `editor_view:move_to_line_end` | + | `CTRL-F` | Move Cursor Right / Accept Autosuggestion | `editor_view:right` | + | `CTRL-G` | Add Selection for Next Occurrence | `editor_view:add_next_occurrence` | + | `CTRL-H` | Remove the Previous Character | `editor_view:backspace` | + | `CTRL-J` | Insert Newline | `editor_view:insert_newline` | + | `CTRL-K` | Cut All Right | `editor_view:cut_all_right` | + | `CTRL-L` | Clear Screen | `input:clear_screen` | + | `CTRL-N` | Move Cursor Down | `editor_view:down` | + | `CTRL-P` | Move Cursor Up | `editor_view:up` | + | | Select to Start of Line | `editor_view:select_to_line_start` | + | `CTRL-SHIFT-B` | Select One Character to the Left | `editor_view:select_left` | + | `CTRL-SHIFT-DOWN` | Add Cursor Below | `editor_view:add_cursor_below` | + | | Select to End of Line | `editor:select_to_line_end` | + | `CTRL-Z` | Undo | `editor:undo` | + | `CTRL-SHIFT-Z` | Redo | `editor:redo` | + | `CTRL-SHIFT-F` | Select One Character to the Right | `editor:select_right` | + | | Select Down | `editor_view:select_down` | + | `CTRL-SHIFT-P` | Select Up | `editor_view:select_up` | + | `CTRL-SHIFT-UP` | Add Cursor Above | `editor_view:add_cursor_above` | + | `CTRL-U` | Copy and Clear Selected Lines | `editor_view:clear_and_copy_lines` | + | `CTRL-W` | Cut Word Left | `editor_view:cut_word_left` | + | `META-.` | Insert Last Word of Previous Command | `editor:insert_last_word_previous_command` | + | `META-A` | Move to the Start of the Paragraph | `editor_view:move_to_paragraph_start` | + | `CTRL-LEFT` | Move Backward One Word | `editor_view:move_backward_one_word` | + | `ALT-D` | Cut Word Right | `editor_view:cut_word_right` | + | `META-E` | Move to the End of the Paragraph | `editor_view:move_to_paragraph_end` | + | `CTRL-RIGHT` | Move Forward One Word | `editor_view:move_forward_one_word` | + | `CTRL-ALT-LEFT` | Move Backward One Subword | `editor_view:move_backward_one_subword` | + | `CTRL-ALT-RIGHT` | Move Forward One Subword | `editor_view:move_forward_one_subword` | + | `SHIFT-META-<` | Move to the Start of the Buffer | `editor_view:move_to_buffer_start` | + | `SHIFT-META->` | Move to the End of the Buffer | `editor_view:move_to_buffer_end` | + | `CTRL-SHIFT-LEFT` | Select One Word to the Left | `editor_view:select_left_by_word` | + | `CTRL-SHIFT-RIGHT` | Select One Word to the Right | `editor_view:select_right_by_word` | + + **Terminal** + + | Shortcut | Command | Action | + | ------------------ | ------------------------------------------------- | -------------------------------------------- | + | `CTRL-ALT-DOWN` | Switch Panes Down | `pane_group:navigate_down` | + | `CTRL-ALT-LEFT` | Switch Panes Left | `pane_group:navigate_left` | + | `CTRL-ALT-RIGHT` | Switch Panes Right | `pane_group:navigate_right` | + | `CTRL-ALT-UP` | Switch Panes Up | `pane_group:navigate_up` | + | `CTRL-ALT-V` | \[a11y] Set Concise Accessibility Announcements | `workspace:set_a11y_concise_verbosity_level` | + | `CTRL-ALT-V` | \[a11y] Set Verbose Accessibility Announcements | `workspace:set_a11y_verbose_verbosity_level` | + | `CTRL-,` | Open Settings | `workspace:show_settings_modal` | + | `CTRL-,` | Open Settings: Account | `workspace:show_settings_account_page` | + | `F3` | Find the Next Occurrence of Your Search Query | `find:find_next_occurrence` | + | `CTRL-SHIFT-P` | Toggle Command Palette | `workspace:toggle_command_palette` | + | | Toggle Mouse Reporting | `workspace:toggle_mouse_reporting` | + | `CTRL-SHIFT-[` | Activate Previous Pane | `pane_group:navigate_prev` | + | `CTRL-SHIFT-]` | Activate Next Pane | `pane_group:navigate_next` | + | | Resize Pane > Move Divider Down | `pane_group:resize_down` | + | `CTRL-CMD-K` | Open Keybindings Editor | `workspace:show_keybinding_settings` | + | | Resize Pane > Move Divider Left | `pane_group:resize_left` | + | | Resize Pane > Move Divider Right | `pane_group:resize_right` | + | | Resize Pane > Move Divider Up | `pane_group:resize_up` | + | `CTRL-SHIFT-/` | Open Resource Center | `workspace:toggle_resource_center` | + | `CTRL-SHIFT-E` | Split Pane Down | `pane_group:add_down` | + | `CTRL-SHIFT-ENTER` | Toggle Maximize Active Pane | `pane_group:toggle_maximize_pane` | + | `SHIFT-F3` | Find the Previous Occurrence of Your Search Query | `find:find_prev_occurrence` | + | | Toggle Navigation Palette | `workspace:toggle_navigation_palette` | + + **Fundamentals** + + | Shortcut | Command | Action | + | ------------------ | -------------------------- | -------------------------------- | + | `CTRL--` | Decrease Font Size | `workspace:decrease_font_size` | + | `CTRL-0` | Reset Font Size to Default | `workspace:reset_font_size` | + | `CTRL-1` | Switch to 1st Tab | `workspace:activate_first_tab` | + | `CTRL-2` | Switch to 2nd Tab | `workspace:activate_second_tab` | + | `CTRL-3` | Switch to 3rd Tab | `workspace:activate_third_tab` | + | `CTRL-4` | Switch to 4th Tab | `workspace:activate_fourth_tab` | + | `CTRL-5` | Switch to 5th Tab | `workspace:activate_fifth_tab` | + | `CTRL-6` | Switch to 6th Tab | `workspace:activate_sixth_tab` | + | `CTRL-7` | Switch to 7th Tab | `workspace:activate_seventh_tab` | + | `CTRL-8` | Switch to 8th Tab | `workspace:activate_eighth_tab` | + | `CTRL-9` | Switch to Last Tab | `workspace:activate_last_tab` | + | `CTRL-=` | Increase Font Size | `workspace:increase_font_size` | + | `CTRL-SHIFT-C` | Copy | `terminal:copy` | + | `CTRL-SHIFT-F` | Find | `terminal:find` | + | `CTRL-SHIFT-V` | Paste | `terminal:paste` | + | `CTRL-SHIFT-T` | Open New Tab | `workspace:open_new_tab` | + | `CTRL-ALT-T` | Reopen Closed Tab | `workspace:reopen_closed_tab` | + | `CTRL-SHIFT-LEFT` | Move Tab Left | `workspace:move_tab_left` | + | `CTRL-SHIFT-RIGHT` | Move Tab Right | `workspace:move_tab_right` | + | `CTRL-PAGEUP` | Activate Previous Tab | `workspace:activate_prev_tab` | + | `CTRL-PAGEDOWN` | Activate Next Tab | `workspace:activate_next_tab` | + </TabItem> +</Tabs> diff --git a/src/content/docs/getting-started/migrate-to-warp/index.mdx b/src/content/docs/getting-started/migrate-to-warp/index.mdx new file mode 100644 index 0000000..dc85062 --- /dev/null +++ b/src/content/docs/getting-started/migrate-to-warp/index.mdx @@ -0,0 +1,23 @@ +--- +title: Migrate to Warp +description: >- + Move your settings and mental model into Warp. Pick the tool you're coming + from for step-by-step guidance, settings-import notes, and where to find + Warp's equivalents of the features you use today. +--- + +Warp users come from every kind of terminal, editor, and AI coding tool. This section has a dedicated page for each of the most common sources, with step-by-step migration guidance, notes on what transfers automatically, and a cross-reference for the Warp features that replace what you use today. + +Pick the tool you're switching from: + +* [**Claude Code**](/getting-started/migrate-to-warp/migrate-to-warp-from-claude-code/) - use Claude Code inside Warp, or switch from Claude Code to Warp's built-in Agent Mode. Covers context, rules, and model setup. +* [**Cursor**](/getting-started/migrate-to-warp/migrate-to-warp-from-cursor/) - use Warp alongside Cursor as your agent terminal, or replace Cursor entirely with Warp's built-in code editor and Agent Mode. +* [**Ghostty**](/getting-started/migrate-to-warp/migrate-to-warp-from-ghostty/) - translate your Ghostty config to Warp and find equivalents for quick terminal, tabs, and GPU rendering. +* [**iTerm2**](/getting-started/migrate-to-warp/migrate-to-warp-from-iterm2/) - use Warp's built-in iTerm2 importer to transfer themes, fonts, keybindings, and hotkey windows in a few clicks. +* [**macOS Terminal**](/getting-started/migrate-to-warp/migrate-to-warp-from-macos-terminal/) - match your Terminal.app setup and discover the split panes, tabs, and Agent Mode features Terminal.app lacks. +* [**VS Code terminal**](/getting-started/migrate-to-warp/migrate-to-warp-from-vs-code-terminal/) - use Warp alongside VS Code for a richer terminal, or replace VS Code entirely with Warp's built-in code editor. +* [**Windows Terminal**](/getting-started/migrate-to-warp/migrate-to-warp-from-windows-terminal/) - map Windows Terminal profiles, PowerShell settings, and color schemes into Warp on Windows. + +## Coming from something else? + +Warp works well for developers migrating from many other sources. If you're switching from a tool that isn't listed above - for example, Alacritty, WezTerm, Kitty, Hyper, or a Linux default like GNOME Terminal or Konsole - drop a note in our [Discord community](https://discord.gg/warpdotdev) so we can prioritize coverage. diff --git a/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-claude-code.mdx b/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-claude-code.mdx new file mode 100644 index 0000000..d1ccffc --- /dev/null +++ b/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-claude-code.mdx @@ -0,0 +1,91 @@ +--- +title: Migrate to Warp from Claude Code +description: >- + Keep using Claude Code in Warp — with rich input, code review, and + notifications — or switch from Claude Code to Warp's Agent Mode as your + primary coding agent. +--- + +Claude Code is different from the other sources in this section: it's not a terminal emulator, it's a CLI agent that runs inside any terminal. Warp is an agentic development environment with a built-in [code editor](/code/code-editor/), [Code Review](/code/code-review/), [team collaboration](/knowledge-and-collaboration/warp-drive/), and [MCP](/agent-platform/capabilities/mcp/) support — so you have two paths to choose from: + +* **[Using Claude Code inside Warp](#using-claude-code-inside-warp)** - you want to keep using Claude Code as your coding agent and run it in Warp's terminal. +* **[Switching to Agent Mode from Claude Code](#switching-to-agent-mode-from-claude-code)** - you want to replace Claude Code with Warp's built-in [Agent Mode](/agent-platform/local-agents/overview/). + +## Using Claude Code inside Warp + +Warp provides first-class support for Claude Code through its [third-party CLI agents](/agent-platform/cli-agents/overview/) integration. Open a new tab and run: + +```bash +claude +``` + +Warp auto-detects Claude Code and unlocks IDE-level features on top of the TUI: + +* **[Rich input editor](/agent-platform/cli-agents/rich-input/)** (`Ctrl+G`) - compose multi-line prompts with `@` mentions, voice input, and slash commands. +* **[Agent notifications](/agent-platform/capabilities/agent-notifications/)** - in-app and desktop alerts when Claude Code needs your input. Requires a one-time plugin install (Warp prompts you). +* **Inline code review** - send review comments directly to the agent from Warp's [Code Review](/code/code-review/) panel. +* **[Vertical tabs with agent metadata](/terminal/windows/vertical-tabs/)** - track multiple Claude Code sessions across tabs with status indicators. +* **[Remote control](/agent-platform/cli-agents/remote-control/)** - share or steer a Claude Code session from another device. +* **[Tab Configs](/terminal/windows/tab-configs/)** - save and reopen Claude Code session layouts. + +For full setup steps (notification plugin, productivity tips, troubleshooting), see [Claude Code in Warp](/agent-platform/cli-agents/claude-code/) and the [How to set up Claude Code](/guides/external-tools/how-to-set-up-claude-code/) guide. + +### Tips + +* **Run Claude Code in [terminal mode](/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes/)**, not Agent Mode. Press `⌘+I` (macOS) or `Ctrl+I` (Linux/Windows) to toggle modes if you're in Agent Mode by accident. +* **`Shift+Enter` for newlines.** Use `Shift+Enter` to insert a newline in Claude Code's prompt. If it submits the message instead, check that you're in terminal mode (not Agent Mode) and that you're on a recent Warp version. +* **Copy/paste handling.** Warp enables bracketed paste by default, so multi-line pastes into Claude Code work without extra configuration. +* **Resuming after a Warp restart.** Warp's [session restoration](/terminal/sessions/session-restoration/) preserves tabs and panes, but not running CLI processes — closing Warp ends Claude Code's session. Use Claude Code's built-in resume options (e.g., `claude --resume`) to continue a conversation after reopening Warp. + +### API keys and authentication + +Claude Code's authentication (API key or Anthropic account) is handled by Claude Code itself, not Warp. Warp does not proxy or modify Claude Code's network calls. Configure your `ANTHROPIC_API_KEY` environment variable via [Warp Drive environment variables](/knowledge-and-collaboration/warp-drive/environment-variables/) to share it across sessions without committing it to shell config files. + +## Switching to Agent Mode from Claude Code + +If you're ready to replace Claude Code with Warp's built-in agent, the core workflow is: + +1. Open a new tab in Warp. +2. To switch to switch to [Agent Mode](/agent-platform/local-agents/overview/) from terminal mode, press `⌘+Enter` (or `Ctrl+Shift+Enter`) +3. Describe what you want in natural language. + +Warp's agent reads your codebase, runs commands, and edits files the same way Claude Code does. + +### What transfers: context and rules + +A recurring question from Claude Code users: **what files and context does Warp's agent read automatically?** Warp picks up project rules from an `AGENTS.md` (or `WARP.md`) at your repo root — the direct equivalent of Claude Code's `CLAUDE.md`. Run `/init` in Agent Mode to generate one, or rename your existing rules file and you're done — no rewriting needed. + +Warp's agent also pulls context from several other explicit sources: + +* **[Codebase Context](/agent-platform/capabilities/codebase-context/)** - when you open a directory, Warp indexes your Git-tracked files so the agent can search and reference your code without you pasting snippets. +* **[Rules](/agent-platform/capabilities/rules/)** - global and project-scoped rules. `AGENTS.md` and `WARP.md` are automatically picked up at the project root; additional rules live in Warp Drive. +* **[Warp Drive](/knowledge-and-collaboration/warp-drive/)** - notebooks, workflows, and environment variables you've saved are available to the agent as context. +* **[Agent Mode context](/knowledge-and-collaboration/warp-drive/agent-mode-context/)** - pin specific files or notebooks to a conversation so the agent always has them in scope. +* **[MCP](/agent-platform/capabilities/mcp/)** - any MCP servers you've configured give the agent access to external tools and data. + +### What to reconfigure + +* **Bring over your `CLAUDE.md`.** Rename it to `AGENTS.md` (or copy it into a Warp [Rule](/agent-platform/capabilities/rules/) if you want it scoped beyond the repo). Warp applies it automatically to new conversations. +* **Set up [MCP servers](/agent-platform/capabilities/mcp/)** you relied on in Claude Code. +* **Pick a model** per conversation using the model selector. See [model choice](/agent-platform/capabilities/model-choice/). Warp supports Claude, GPT, Gemini, and Auto. +* **Configure [agent profiles and permissions](/agent-platform/capabilities/agent-profiles-permissions/)** for what the agent can auto-execute. + +### Key differences from Claude Code + +* **Tight terminal integration.** Agent Mode runs inside Warp and sees the full state of your terminal session — open files, command history, environment variables — without needing you to paste context. +* **Parallel agents.** Warp runs multiple agent conversations across tabs simultaneously, each with its own state, which you can track in the Agent Management Panel. +* **Code Review built in.** Agent-generated diffs open in Warp's [Code Review](/code/code-review/) panel, not the terminal. +* **Cloud orchestration.** Long-running or scheduled agent work can be offloaded to [Oz](/agent-platform/cloud-agents/overview/). + +## Warp-native equivalents + +Claude Code concepts and their closest Warp analog: + +| From Claude Code | In Warp | +| --- | --- | +| `CLAUDE.md` | `AGENTS.md` (or `WARP.md`) at the project root, picked up as a [Rule](/agent-platform/capabilities/rules/) | +| Claude Code slash commands | Warp's own [slash commands](/agent-platform/capabilities/slash-commands/) (`/init`, `/plan`, `/model`, etc.); save your own as [Warp Drive prompts](/knowledge-and-collaboration/warp-drive/prompts/) | +| Tool definitions | [MCP](/agent-platform/capabilities/mcp/) | +| Resume conversation | Warp persists agent conversations per tab; pair with [tab configs](/terminal/windows/tab-configs/) to reopen the same project layout | + +For a deeper tour of Agent Mode, see [Coding in Warp](/getting-started/quickstart/coding-in-warp/) and the [Warp Agents docs](/agent-platform/local-agents/overview/). diff --git a/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-cursor.mdx b/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-cursor.mdx new file mode 100644 index 0000000..fa431f3 --- /dev/null +++ b/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-cursor.mdx @@ -0,0 +1,78 @@ +--- +title: Migrate to Warp from Cursor +description: >- + Reconfigure your terminal and agent settings when switching to Warp from + Cursor, or run Warp alongside Cursor as your agent terminal. +--- + +Warp gives Cursor users two clean migration paths: keep Cursor as your editor and use Warp for terminal and agent work, or move fully to Warp's built-in code editor and Agent Mode. This page walks through both options. + +## What transfers automatically + +Warp doesn't ship a Cursor importer. Cursor is built on the VS Code codebase, so its terminal settings live in `settings.json` under keys like `terminal.integrated.fontFamily` and `terminal.integrated.defaultProfile.*`. Open your user settings with **Command Palette** > **Preferences: Open User Settings (JSON)** to reference them while you reconfigure Warp. + +## Use Warp's agent to migrate your settings (recommended) + +The fastest way to bring over your Cursor terminal setup is to ask Warp's agent to translate your `settings.json` directly. Warp ships a [`settings.toml` file](/terminal/settings/) and a bundled `modify-settings` skill that lets the agent read your existing config and write equivalent values into Warp's settings. + +1. In Warp, open a new tab and switch to [Agent Mode](/agent-platform/local-agents/overview/) with `⌘+I` (macOS) or `Ctrl+I` (Linux/Windows). +2. Paste a prompt like: + + > Read my Cursor `settings.json` (`~/Library/Application Support/Cursor/User/settings.json` on macOS) and port the equivalent terminal settings (font, cursor style, default profile) into my Warp `settings.toml` using the `modify-settings` skill. Show me a diff before applying. + +3. Review the proposed diff and approve. Warp hot-reloads `settings.toml`, so changes take effect immediately. + +If you'd rather configure each setting manually through the Settings UI, the steps below cover the most common cases. + +## What to reconfigure manually + +### Terminal settings + +Terminal settings in Cursor follow the same schema as VS Code. The migration steps are identical to the VS Code terminal migration - see [Migrate to Warp from VS Code terminal](/getting-started/migrate-to-warp/migrate-to-warp-from-vs-code-terminal/) for step-by-step guidance on shell, font, theme, and keybinding setup. + +### Agent and AI settings + +Cursor's Composer and Agent features don't have a one-to-one migration path - they map to different Warp concepts. + +* **Composer / Agent** in Cursor maps to Warp's [Agent Mode](/agent-platform/local-agents/overview/). Start an agent conversation in any tab. +* **Rules files** (`.cursorrules`) - Warp uses [Rules](/agent-platform/capabilities/rules/) stored in Warp Drive or committed to your repo as `AGENTS.md` (or `WARP.md`). Run `/init` in Agent Mode to generate an `AGENTS.md`, or copy your `.cursorrules` content directly. +* **MCP servers** - Warp supports MCP natively. See [MCP](/agent-platform/capabilities/mcp/) for configuration. + +### Model choice + +Cursor lets you pick a model per conversation. Warp does the same - use the model selector in any agent conversation. See [model choice](/agent-platform/capabilities/model-choice/). + +### Keybindings + +Warp's [keyboard shortcuts](/getting-started/keyboard-shortcuts/) differ from Cursor's. Most notably, `⌘+I` (or `Ctrl+I` on Linux/Windows) toggles between terminal and Agent Mode. From terminal mode you can also press `⌘+Enter` (or `Ctrl+Shift+Enter`) as an alternate shortcut into Agent Mode. + +## Choosing your setup + +### Use Warp alongside Cursor + +Keep Cursor as your editor for tight in-file AI assistance, and use Warp as the terminal you switch to for: + +* Long-running commands and SSH. +* [Agent Mode](/agent-platform/local-agents/overview/) conversations that execute commands, not just edit files. +* [Code Review](/code/code-review/) for managing diffs. +* [Warp Drive](/knowledge-and-collaboration/warp-drive/) for team knowledge. + +### Replace Cursor with Warp + +Warp's built-in [code editor](/code/code-editor/) supports Language Server Protocol, a [file tree](/code/code-editor/file-tree/), [find and replace](/code/code-editor/find-and-replace/), and [Vim keybindings](/code/code-editor/code-editor-vim-keybindings/). Combined with Agent Mode, Code Review, and Warp Drive, the full Cursor workflow is reachable in Warp without a separate editor. + +## Warp-native equivalents + +Cursor features and their Warp counterparts: + +| From Cursor | In Warp | +| --- | --- | +| Composer / Agent panel | [Agent Mode](/agent-platform/local-agents/overview/) in any tab (toggle with `⌘+I`) | +| Agent tabs | Multiple [agents in parallel](/agent-platform/local-agents/overview/) across tabs | +| `.cursorrules` | `AGENTS.md` / `WARP.md` at the project root, picked up as a [Rule](/agent-platform/capabilities/rules/) | +| MCP servers | [MCP](/agent-platform/capabilities/mcp/) | +| Model choice per conversation | [Model selector](/agent-platform/capabilities/model-choice/) | +| Codebase indexing | [Codebase Context](/agent-platform/capabilities/codebase-context/) | +| Inline diff review | [Code Review](/code/code-review/) | + +See [Coding in Warp](/getting-started/quickstart/coding-in-warp/) for a tour of the development workflow. diff --git a/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-ghostty.mdx b/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-ghostty.mdx new file mode 100644 index 0000000..634479d --- /dev/null +++ b/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-ghostty.mdx @@ -0,0 +1,70 @@ +--- +title: Migrate to Warp from Ghostty +description: >- + Moving to Warp from Ghostty? Here's how to bring over your themes, fonts, + and keybindings, plus where to find Warp's equivalents for Ghostty's native + features. +--- + +Warp gives Ghostty users a fast path to bring over themes, fonts, and keybindings — plus native equivalents for the Ghostty features you rely on, from the quick terminal to native tabs and splits. + +## What transfers automatically + +Warp doesn't ship a Ghostty importer, but it can do most of the work for you agentically. Ghostty stores its configuration in a plain-text key-value file at `~/.config/ghostty/config`. + +## Use Warp's agent to migrate your settings (recommended) + +The fastest way to bring over your Ghostty setup is to ask Warp's agent to translate your config directly. Warp ships a [`settings.toml` file](/terminal/settings/) and a bundled `modify-settings` skill that lets the agent read your existing config and write equivalent values into Warp's settings, including translating your Ghostty theme into a Warp [custom theme](/terminal/appearance/custom-themes/). + +1. In Warp, open a new tab and switch to [Agent Mode](/agent-platform/local-agents/overview/) with `⌘+I` (macOS) or `Ctrl+I` (Linux/Windows). +2. Paste a prompt like: + + > Read my Ghostty config at `~/.config/ghostty/config` and any referenced theme files in `~/.config/ghostty/themes/`. Port the equivalent settings (theme, font, keybindings, shell) into my Warp `settings.toml` using the `modify-settings` skill, and create a matching custom theme. Show me a diff before applying. + +3. Review the proposed diff and approve. Warp hot-reloads `settings.toml`, so changes take effect immediately. + +If you'd rather configure each setting manually through the Settings UI, the steps below cover the most common cases. + +## What to reconfigure manually + +### Theme and colors + +1. Open **Settings** > **Appearance** > **Themes** in Warp. +2. Pick a built-in theme that matches your Ghostty setup, or [create a custom theme](/terminal/appearance/custom-themes/) by translating your Ghostty colors into a YAML theme file. +3. Ghostty's theme files live in `~/.config/ghostty/themes/`. Open the file named in your Ghostty `theme` setting to copy the foreground, background, and 16 ANSI color values. + +### Font and text + +1. In **Settings** > **Appearance** > **Text, fonts, & cursor**, match your Ghostty `font-family` and `font-size` values. +2. If you use font ligatures, ensure **Ligatures** is enabled. + +### Keybindings + +Warp's [default keyboard shortcuts](/getting-started/keyboard-shortcuts/) cover most Ghostty bindings. For custom bindings from your Ghostty `keybind` lines, open **Settings** > **Keyboard shortcuts** and add them manually. + +### Shell and prompt + +Warp detects your login shell automatically. To override it, go to **Settings** > **Features** > **Session** and pick a shell from **Startup shell for new sessions**. + +For prompts, choose between Warp's [native prompt](/terminal/appearance/prompt/#warp-prompt) (drag-and-drop context chips) or the [shell prompt (PS1)](/terminal/appearance/prompt/#custom-prompt) if you want to keep your existing prompt configuration. + +### Quick terminal (Quake mode) + +Configure Warp's equivalent via **Settings** > **Features** > **Window** > **Global hotkey**. See [global hotkey](/terminal/windows/global-hotkey/) for the full configuration. + +## Warp-native equivalents + +Features Ghostty users commonly miss, and where they live in Warp: + +| From Ghostty | In Warp | +| --- | --- | +| Quick terminal / dropdown window | [Global hotkey](/terminal/windows/global-hotkey/) | +| Native tabs and splits | [Tabs](/terminal/windows/tabs/), [vertical tabs](/terminal/windows/vertical-tabs/), [split panes](/terminal/windows/split-panes/) | +| Command palette | [Command Palette](/terminal/command-palette/) (`⌘+P` on macOS, `Ctrl+Shift+P` on Linux) | +| GPU-accelerated rendering | GPU-rendered natively on all supported platforms | +| Kitty graphics protocol | Image rendering for most common workflows (see [more features](/terminal/more-features/)) | +| Shaders and custom visual effects | Not supported; closest: [size, opacity, and blurring](/terminal/appearance/size-opacity-blurring/) + [pane dimming](/terminal/appearance/pane-dimming/) | + +Beyond parity, Warp adds [Agent Mode](/agent-platform/local-agents/overview/), [Code Review](/code/code-review/), and [Warp Drive](/knowledge-and-collaboration/warp-drive/) for AI-assisted development and team collaboration. + +For more on what you can configure, see [Customizing Warp](/getting-started/quickstart/customizing-warp/). diff --git a/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-iterm2.mdx b/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-iterm2.mdx new file mode 100644 index 0000000..93d516b --- /dev/null +++ b/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-iterm2.mdx @@ -0,0 +1,72 @@ +--- +title: Migrate to Warp from iTerm2 +description: >- + Import your iTerm2 profile into Warp to transfer themes, fonts, keybindings, + hotkey windows, and more in a few clicks. +--- + +Warp imports your iTerm2 profile automatically, bringing over theme, font, keybindings, hotkey window, and more in a few clicks. This page walks through the importer, what it covers, and what to reconfigure manually after. + +## What transfers automatically + +Warp ships a built-in iTerm2 importer that reads your default profile from `~/Library/Preferences/com.googlecode.iterm2.plist`. It imports: + +* **Theme** - foreground, background, cursor, and all 16 ANSI colors (light and dark variants if configured). +* **Font** - family and size (when the font exists on your system and is supported by Warp). +* **Default shell** - if you've set a custom Command in your iTerm2 profile. +* **Working directory behavior** - Warp translates iTerm2's "Reuse previous session's directory" and similar options. +* **Window dimensions** - rows and columns. +* **Opacity and blur.** +* **Copy-on-select, mouse and scroll reporting, and Option-as-Meta settings.** +* **Global hotkey** - if you use a hotkey window or hotkey activation, Warp maps it. + +To run the importer: + +1. In Warp, open the [Command Palette](/terminal/command-palette/). +2. Search for **Import External Settings**. +3. Select **iTerm2 Profile: Default**. Warp only imports the profile marked as your Default Bookmark in iTerm2. +4. Choose which settings to keep or skip on the preview screen. + +![Select a settings profile to import](../../../../assets/terminal/migrate-to-warp.png) + +## Use Warp's agent for follow-up settings + +If the importer doesn't pick up something you care about — a non-default profile, an unusual keybinding, a specific setting — ask Warp's agent to translate it directly. Warp ships a [`settings.toml` file](/terminal/settings/) and a bundled `modify-settings` skill that lets the agent read your iTerm2 plist and write equivalent values into Warp's settings. + +1. In Warp, switch to [Agent Mode](/agent-platform/local-agents/overview/) with `⌘+I`. +2. Paste a prompt like: + + > Read my iTerm2 preferences with `defaults read com.googlecode.iterm2` and port any settings that the importer didn't cover (extra profiles, custom keybindings) into my Warp `settings.toml` using the `modify-settings` skill. Show me a diff before applying. + +3. Review the proposed diff and approve. Warp hot-reloads `settings.toml`. + +## What to reconfigure manually + +A few iTerm2 features don't map directly and need a manual pass after import: + +* **Multiple profiles.** Warp imports only your Default profile. If you rely on multiple iTerm2 profiles, create equivalent [tab configs](/terminal/windows/tab-configs/) in Warp. +* **Keyboard shortcuts.** Warp's [keyboard shortcuts](/getting-started/keyboard-shortcuts/) cover most iTerm2 bindings out of the box, but custom bindings need to be recreated in **Settings** > **Keyboard shortcuts**. +* **Split panes and arrangements.** Rebuild using [split panes](/terminal/windows/split-panes/) and [tab configs](/terminal/windows/tab-configs/). +* **Triggers.** Warp doesn't have a direct equivalent. Reach similar outcomes through [YAML workflows](/terminal/entry/yaml-workflows/) or Agent Mode. + +### Choose your prompt + +After the import, choose which [prompt](/terminal/appearance/prompt/) to use: + +1. [**Warp prompt**](/terminal/appearance/prompt/#warp-prompt) - Warp's native prompt with drag-and-drop context chips for git branch, directory, timestamps, and more. Configure in **Settings** > **Appearance** > **Prompt**. +2. [**Shell prompt (PS1)**](/terminal/appearance/prompt/#custom-prompt) - inherits your existing shell prompt configuration unchanged. Pick this if you want Warp to match your iTerm2 prompt exactly. + +## Warp-native equivalents + +Features switchers commonly look for after leaving iTerm2, and where they live in Warp: + +| From iTerm2 | In Warp | +| --- | --- | +| Hotkey window (Quake mode) | [Global hotkey](/terminal/windows/global-hotkey/) (imported automatically when detected in your iTerm2 profile) | +| Triggers | [YAML workflows](/terminal/entry/yaml-workflows/) for repeatable actions; Agent Mode for pattern-based automation | +| Profiles | [Tab configs](/terminal/windows/tab-configs/) for layouts; [Warp Drive](/knowledge-and-collaboration/warp-drive/) for shared team setups | +| Autocomplete menu | [Autosuggestions](/terminal/command-completions/autosuggestions/) + [tab completions](/terminal/command-completions/completions/) | +| Instant replay | [Session restoration](/terminal/sessions/session-restoration/) | +| Password manager integration | [Warp Drive environment variables](/knowledge-and-collaboration/warp-drive/environment-variables/) | + +For more on what you can configure after migrating, see the [Warp quickstart](/quickstart/) and [Customizing Warp](/getting-started/quickstart/customizing-warp/). diff --git a/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-macos-terminal.mdx b/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-macos-terminal.mdx new file mode 100644 index 0000000..1d04d46 --- /dev/null +++ b/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-macos-terminal.mdx @@ -0,0 +1,74 @@ +--- +title: Migrate to Warp from macOS Terminal +description: >- + Switching to Warp from the default macOS Terminal app? Here's a quick + reference for matching your existing setup and discovering what Warp adds + beyond the basics. +--- + +Warp gives Terminal.app users everything they already have — shell, theme, font, prompt — plus split panes, tabs, blocks, and Agent Mode for an AI-assisted workflow. This page walks through both an agent-driven migration and the manual GUI steps. + +## What transfers automatically + +Warp doesn't ship a Terminal.app importer, but it can do most of the work for you agentically. Most Terminal.app users run near-default settings, so the migration usually takes only a few minutes either way. + +## Use Warp's agent to migrate your settings (recommended) + +The fastest way to bring over a Terminal.app theme is to ask Warp's agent to translate it directly. Warp ships a [`settings.toml` file](/terminal/settings/) and a bundled `modify-settings` skill that lets the agent read your Terminal.app preferences and write equivalent values into Warp's settings, including creating a matching [custom theme](/terminal/appearance/custom-themes/). + +1. In Warp, open a new tab and switch to [Agent Mode](/agent-platform/local-agents/overview/) with `⌘+I`. +2. Paste a prompt like: + + > Read my Terminal.app preferences with `defaults read com.apple.Terminal` and port the active profile (theme, font, window size) into my Warp `settings.toml` using the `modify-settings` skill. Create a matching custom theme. Show me a diff before applying. + +3. Review the proposed diff and approve. Warp hot-reloads `settings.toml`. + +If you'd rather configure each setting manually through the Settings UI, the steps below cover the most common cases. + +## What to reconfigure manually + +### Shell + +Warp auto-detects your login shell on first launch. macOS has shipped with `zsh` as the default since Catalina (2019); if you changed your shell with `chsh`, Warp picks that up too. + +To change it later, go to **Settings** > **Features** > **Session** and pick a shell from **Startup shell for new sessions**. + +### Theme and colors + +Terminal.app ships with a handful of profiles (Basic, Pro, Homebrew, Ocean, etc.). Match them in Warp: + +1. Open **Settings** > **Appearance** > **Themes**. +2. Pick a preset theme. Warp's built-in library includes many themes similar to Terminal.app's defaults. +3. For exact color matches, [create a custom theme](/terminal/appearance/custom-themes/) using the ANSI color values you can inspect in Terminal.app's **Settings** > **Profiles** > **Text** tab. + +### Font + +1. In **Settings** > **Appearance** > **Text, fonts, & cursor**, pick your font family and size to match what you use in Terminal.app. + +### Window size and transparency + +Configure in **Settings** > **Appearance** > **Size, opacity, & blurring**. See [size, opacity, and blurring](/terminal/appearance/size-opacity-blurring/). + +### Prompt + +Terminal.app uses whatever prompt your shell's PS1 (or zsh's PROMPT) defines. In Warp, choose: + +1. [**Warp prompt**](/terminal/appearance/prompt/#warp-prompt) - Warp's native prompt with drag-and-drop chips for git branch, directory, and more. +2. [**Shell prompt (PS1)**](/terminal/appearance/prompt/#custom-prompt) - keeps your existing shell prompt exactly as it appears in Terminal.app. + +Configure in **Settings** > **Appearance** > **Prompt**. + +## Warp-native equivalents + +Most Terminal.app features have a Warp equivalent with additional capabilities on top: + +| From Terminal.app | In Warp | +| --- | --- | +| Profiles | [Tab configs](/terminal/windows/tab-configs/) for layouts and startup commands; [themes](/terminal/appearance/themes/) for appearance (Warp has no single profile object) | +| Window groups / arrangements | [Tab configs](/terminal/windows/tab-configs/) | +| Tabs | [Tabs](/terminal/windows/tabs/), [vertical tabs](/terminal/windows/vertical-tabs/) | +| Split panes | [Split panes](/terminal/windows/split-panes/) (Terminal.app doesn't support) | +| Copy-on-select | **Settings** > **Features** > **Session** | +| Inspector | [Command inspector](/terminal/editor/command-inspector/) (exit code, duration, working directory) | + +Beyond matching Terminal.app, Warp adds [Agent Mode](/agent-platform/local-agents/overview/) for natural-language commands, [blocks](/terminal/blocks/) for structured command output, and [Warp Drive](/knowledge-and-collaboration/warp-drive/) for shared workflows. New to Warp? Start with the [Warp quickstart](/quickstart/). diff --git a/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-vs-code-terminal.mdx b/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-vs-code-terminal.mdx new file mode 100644 index 0000000..01d1d5a --- /dev/null +++ b/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-vs-code-terminal.mdx @@ -0,0 +1,79 @@ +--- +title: Migrate to Warp from VS Code terminal +description: >- + Replicate your VS Code integrated terminal setup in Warp - shell, fonts, + keybindings - or run Warp alongside VS Code as a richer terminal. +--- + +Warp lets VS Code users choose their own path: keep VS Code for editing and run Warp as the terminal alongside it, or replace both with Warp's built-in code editor. This page walks through reconfiguring your terminal settings for either path. + +## What transfers automatically + +Warp doesn't ship a VS Code importer — it's a standalone application, not a VS Code extension — but it can do most of the work for you agentically. Your VS Code terminal settings live in your user `settings.json` under keys like: + +```json +"terminal.integrated.defaultProfile.osx": "zsh", +"terminal.integrated.fontFamily": "MesloLGS NF", +"terminal.integrated.fontSize": 14, +"terminal.integrated.cursorStyle": "line", +"terminal.integrated.profiles.osx": { ... } +``` + +## Use Warp's agent to migrate your settings (recommended) + +The fastest way to bring over your VS Code terminal setup is to ask Warp's agent to translate `settings.json` directly. Warp ships a [`settings.toml` file](/terminal/settings/) and a bundled `modify-settings` skill that lets the agent read your existing config and write equivalent values into Warp's settings. + +1. In Warp, open a new tab and switch to [Agent Mode](/agent-platform/local-agents/overview/) with `⌘+I` (macOS) or `Ctrl+I` (Linux/Windows). +2. Paste a prompt like: + + > Read my VS Code `settings.json` (`~/Library/Application Support/Code/User/settings.json` on macOS) and port the equivalent terminal settings (`terminal.integrated.*` keys) into my Warp `settings.toml` using the `modify-settings` skill. Show me a diff before applying. + +3. Review the proposed diff and approve. Warp hot-reloads `settings.toml`. + +If you'd rather configure each setting manually through the Settings UI, the steps below cover the most common cases. + +## What to reconfigure manually + +### Shell + +Warp auto-detects your login shell. To override - for example, to match `terminal.integrated.defaultProfile.*` - go to **Settings** > **Features** > **Session** and pick a shell from **Startup shell for new sessions**. + +### Font and cursor + +In Warp's **Settings** > **Appearance** > **Text, fonts, & cursor**, set the font family and size to match `terminal.integrated.fontFamily` and `terminal.integrated.fontSize`. + +### Theme + +VS Code's terminal uses the color scheme from your overall editor theme. In Warp, pick a comparable theme from **Settings** > **Appearance** > **Themes**, or [create a custom theme](/terminal/appearance/custom-themes/) that matches your VS Code theme's `terminal.*` color tokens. + +### Keybindings + +Warp's [default keyboard shortcuts](/getting-started/keyboard-shortcuts/) are largely consistent with VS Code terminal shortcuts (splits, new tab, find). For any custom bindings you configured in VS Code, add them in Warp's **Settings** > **Keyboard shortcuts**. + +## Choosing your setup + +### Use Warp alongside VS Code + +Many developers keep VS Code as their editor and use Warp as the terminal they switch to for long-running commands, SSH sessions, or AI-assisted workflows. No changes to VS Code needed - just install Warp and open it when you want a richer terminal. + +VS Code's integrated terminal still works; use it for quick one-off commands, and jump to Warp when you need [blocks](/terminal/blocks/), [Agent Mode](/agent-platform/local-agents/overview/), or [persistent sessions](/terminal/sessions/session-restoration/). + +### Replace VS Code with Warp + +Warp includes a built-in [code editor](/code/code-editor/) with Language Server Protocol (LSP) support, a [file tree](/code/code-editor/file-tree/), [find and replace](/code/code-editor/find-and-replace/), and [Vim keybindings](/code/code-editor/code-editor-vim-keybindings/). Combined with [Code Review](/code/code-review/), many developers use Warp as their primary editor and drop VS Code entirely. + +Open a directory with `warp .` from the command line to start editing. + +## Warp-native equivalents + +VS Code terminal features and their Warp equivalents: + +| From VS Code terminal | In Warp | +| --- | --- | +| Split terminal | [Split panes](/terminal/windows/split-panes/) | +| Multiple terminals (tab strip) | [Tabs](/terminal/windows/tabs/), [vertical tabs](/terminal/windows/vertical-tabs/) | +| Tasks (`tasks.json`) | [YAML workflows](/terminal/entry/yaml-workflows/) or [tab configs](/terminal/windows/tab-configs/) | +| Terminal profiles | [Tab configs](/terminal/windows/tab-configs/) + per-session shell overrides | +| Shell integration | Built in via [Warpify](/terminal/warpify/); enables working-directory tracking and command-level [blocks](/terminal/blocks/) | + +For an overview of what Warp adds beyond a terminal, see [Coding in Warp](/getting-started/quickstart/coding-in-warp/). diff --git a/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-windows-terminal.mdx b/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-windows-terminal.mdx new file mode 100644 index 0000000..247f6a0 --- /dev/null +++ b/src/content/docs/getting-started/migrate-to-warp/migrate-to-warp-from-windows-terminal.mdx @@ -0,0 +1,77 @@ +--- +title: Migrate to Warp from Windows Terminal +description: >- + Switching from Windows Terminal and PowerShell to Warp on Windows? Here's + how to reconfigure profiles, shells, fonts, and keybindings, and where to + find Warp's equivalents for Windows Terminal features. +--- + +Warp on Windows covers everything you use Windows Terminal for today — profiles, PowerShell, color schemes, keybindings — with Agent Mode and blocks on top. This page walks through the migration. + +## What transfers automatically + +Warp doesn't ship a Windows Terminal importer, but it can do most of the work for you agentically. Windows Terminal stores its settings in a single JSON file at: + +```powershell +%LOCALAPPDATA%\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json +``` + +## Use Warp's agent to migrate your settings (recommended) + +The fastest way to bring over your Windows Terminal setup is to ask Warp's agent to translate `settings.json` directly. Warp ships a [`settings.toml` file](/terminal/settings/) and a bundled `modify-settings` skill that lets the agent read your existing config and write equivalent values into Warp's settings, including translating your color schemes into a Warp [custom theme](/terminal/appearance/custom-themes/). + +1. In Warp, open a new tab and switch to [Agent Mode](/agent-platform/local-agents/overview/) with `Ctrl+I`. +2. Paste a prompt like: + + > Read my Windows Terminal `settings.json` at `%LOCALAPPDATA%\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json` and port the active profile and color scheme into my Warp `settings.toml` using the `modify-settings` skill. Create a matching custom theme. Show me a diff before applying. + +3. Review the proposed diff and approve. Warp hot-reloads `settings.toml`. + +If you'd rather configure each setting manually through the Settings UI, the steps below cover the most common cases. + +## What to reconfigure manually + +### Default shell + +Warp on Windows supports PowerShell (`pwsh` and `powershell.exe`), Command Prompt (`cmd`), bash, zsh, and fish. Warp auto-detects your login shell; to override, go to **Settings** > **Features** > **Session** and pick a shell from **Startup shell for new sessions**. + +If you use PowerShell modules or a custom `$PROFILE`, Warp loads them the same way Windows Terminal does. + +### Profiles + +Windows Terminal uses profiles to group shell, theme, starting directory, and font together. Warp doesn't have a single profile concept; instead, match each dimension separately: + +* **Shell** - **Settings** > **Features** > **Session**. +* **Starting directory** - **Settings** > **Features** > **Session** > Working directory. +* **Font family, size** - **Settings** > **Appearance** > **Text, fonts, & cursor**. +* **Color scheme** - **Settings** > **Appearance** > **Themes**. Translate your Windows Terminal color scheme into a [custom Warp theme](/terminal/appearance/custom-themes/) using the same 16 ANSI color values. +* **Reusable layouts** - create a [tab config](/terminal/windows/tab-configs/) for each workflow that used to be a profile. + +### Color scheme + +Windows Terminal's `schemes` array defines foreground, background, cursor, and ANSI colors. To match an existing scheme: + +1. Copy the color values from the scheme you use in your `settings.json`. +2. Open **Settings** > **Appearance** > **Themes** in Warp and either pick a preset that matches or [create a custom theme](/terminal/appearance/custom-themes/). + +### Keybindings + +Warp's [default keyboard shortcuts](/getting-started/keyboard-shortcuts/) cover most Windows Terminal bindings. For custom bindings from `settings.json`'s `actions` array, add them in **Settings** > **Keyboard shortcuts**. + +### Prompt + +If you use `oh-my-posh` or a custom PowerShell prompt, it continues to work in Warp. To choose between Warp's native prompt and your existing shell prompt, go to **Settings** > **Appearance** > **Prompt**. See [prompt](/terminal/appearance/prompt/). + +## Warp-native equivalents + +Features Windows Terminal users commonly look for in Warp: + +| From Windows Terminal | In Warp | +| --- | --- | +| Profiles | [Tab configs](/terminal/windows/tab-configs/) + [themes](/terminal/appearance/themes/) + per-session shell settings | +| Tabs and panes | [Tabs](/terminal/windows/tabs/), [vertical tabs](/terminal/windows/vertical-tabs/), [split panes](/terminal/windows/split-panes/) | +| Command palette | [Command Palette](/terminal/command-palette/) (`Ctrl+Shift+P`) | +| Oh My Posh prompts | Keep using them; pick [Shell prompt (PS1)](/terminal/appearance/prompt/#custom-prompt) in Warp | +| Quake mode | [Global hotkey](/terminal/windows/global-hotkey/) | + +Beyond Windows Terminal's feature set, Warp adds [Agent Mode](/agent-platform/local-agents/overview/), [blocks](/terminal/blocks/), and [Warp Drive](/knowledge-and-collaboration/warp-drive/). See [Warp for Windows installation](/getting-started/quickstart/installation-and-setup/) if you haven't installed yet. diff --git a/src/content/docs/getting-started/quickstart/coding-in-warp.mdx b/src/content/docs/getting-started/quickstart/coding-in-warp.mdx new file mode 100644 index 0000000..321f5ca --- /dev/null +++ b/src/content/docs/getting-started/quickstart/coding-in-warp.mdx @@ -0,0 +1,82 @@ +--- +title: Coding in Warp +description: >- + Agents can generate and edit code directly from within Warp. +--- + +When you enter a Git repo for the first time, Warp will enter an initialization flow to index your codebase and generate an AGENTS.md file. + +As you're in the repo, Warp will enter an advanced code generation flow that supports both single-line and multi-file changes when it detects an opportunity to write code. + +For example, Warp may write code when you prompt: + +* **Code creation**: “Write a function in JavaScript to debounce an input” +* **Based on error outputs, suggest fixes**: “Fix this TypeScript error.” +* **Edit a single file**: “Update all instances of ‘var’ to ‘let’ in this file.” +* **Make batch changes**: “Add headers to all .py files in this directory” + +**The best way to experience this is to try it yourself —** [_open the Prompt below in Warp_](https://app.warp.dev/drive/prompt/Generate-a-custom-Warp-theme-K8oloLrCZAHuaYKfz2cNqI) + +```text +Detect the correct Warp themes directory based on the current operating system: +- On macOS, use ~/.warp/themes/ +- On Linux, use ${XDG_DATA_HOME:-$HOME/.local/share}/warp-terminal/themes/ +- On Windows, use $env:APPDATA\warp\Warp\data\themes\ + +Create the directory if it doesn’t already exist. + +Then, generate a custom Warp theme named {{theme_name}} in valid YAML format, following the official structure from Warp’s documentation. Exclude the background_image field, and do not include any extra or missing fields. Save the theme as {{theme_name}}.yaml in the detected themes directory. + +Once the theme is created and verified, confirm completion by telling me where the theme file was saved. +``` +--- + +### Context + +#### Codebase Context + +Warp can index your Git-tracked codebases to help agents understand your code and generate accurate, context-aware responses. **No code is stored on Warp servers**. + +You can view and manage your indexed codebases in **Settings** > **Code** > **Indexing and projects** under "Initialized/ indexed folders". You can also specify whether to automatically index new folders as you navigate them. + +If your codebase is large, you can exclude specific files by adding them to a `.warpindexingignore` file. + +#### Other types of context + +You can provide different types of input as context directly to the agent to guide its behavior and improve response quality. This includes: + +* [Blocks](/agent-platform/local-agents/agent-context/blocks-as-context/) from your terminal output +* [Images](/agent-platform/local-agents/agent-context/images-as-context/) +* [Files and code](/agent-platform/local-agents/agent-context/using-to-add-context/) (using the @ symbol) +* [Public websites](/agent-platform/local-agents/agent-context/urls-as-context/) via URLs + +#### Warp Drive as Context + +Agents pull directly from your [**Warp Drive**](/knowledge-and-collaboration/warp-drive/) contents to generate more accurate responses -- including your **Workflows**, **Notebooks**, **Prompts**, and **Environment Variables**. + +* When used, context appears under the “References” or “Derived from” section in the conversation. +* This setting is **enabled by default** and can be managed via: **Settings** > **Agents** > **Knowledge** > **Warp Drive as Agent Mode Context**. + +#### Rules + +**Rules** let you provide persistent context to Agents, enabling smarter and more personalized responses. + +You can create global rules (accessed through [Warp Drive](/knowledge-and-collaboration/warp-drive/) >**Personal** > **Rules**) or project scoped rules, defined in an `AGENTS.md` file. Note: the filename must be in all caps for Warp to recognize it. + +**Examples of Rules include:** + +* Coding standards and best practices +* Project- or workspace-specific guidelines +* Personal preferences for tools, formatting, or behavior + +How to access project-specific Rules + +1. From the file-searcher, CMD+O and search "AGENTS.md" +2. From the file tree, click the "code" icon when in a repo + +How to access Global Rules + +1. From the [Warp Drive](/knowledge-and-collaboration/warp-drive/) >**Personal** > **Rules** +2. From the [Command Palette](/terminal/command-palette/), search for "Open AI Rules" +3. From the Settings panel, **Settings** > **Agents** > **Knowledge** > **Manage Rules** +4. From the macOS Menu, `AI > Open Rules` diff --git a/src/content/docs/getting-started/quickstart/customizing-warp.mdx b/src/content/docs/getting-started/quickstart/customizing-warp.mdx new file mode 100644 index 0000000..12a7501 --- /dev/null +++ b/src/content/docs/getting-started/quickstart/customizing-warp.mdx @@ -0,0 +1,84 @@ +--- +title: Customizing Warp +description: >- + A complete guide to customizing Warp: themes, vertical tabs, tab configs, + prompt chips, keybindings, AI models, and more. +--- + +Warp is deeply customizable. Whether you use Warp primarily as a modern terminal or as an AI-powered development environment, you can tailor the experience to fit how you work. Configure the terminal side (themes, keybindings, vertical tabs, tab configs) and the AI side (model choice, agent autonomy, default mode) independently. + +Use the quick-reference table to find what you need, or browse the sections below for more details. If you want to go further than configuration, Warp's client is open source under [AGPL v3](https://github.com/warpdotdev/warp/blob/master/LICENSE) — see [Contributing to Warp](/support-and-community/community/contributing/) to build a custom variant or contribute changes upstream. + +## Quick reference + +| What to customize | Where to find it | Quick action | +| --- | --- | --- | +| Theme | **Settings** > **Appearance** | Pick a preset or [create a custom YAML theme](/terminal/appearance/custom-themes/) | +| Prompt chips | Right-click prompt area > **Edit prompt** | Drag and drop context chips (directory, git branch, time, etc.) | +| AI model | Model selector in agent conversation | Choose Claude, GPT, Gemini, or Auto | +| Keybindings | **Settings** > **Keyboard shortcuts** | Import from another terminal or set custom shortcuts | +| Vertical tabs | **Settings** > **Appearance** > **Tabs** | Switch to a sidebar tab layout for more horizontal space | +| Tab configs | **Settings** > **Features** or `/` menu | Save and restore tab layouts with startup commands | +| Settings file | **Open settings file** button in the Settings footer | Edit [`settings.toml`](/terminal/settings/) directly for version control and scripting | +| Input format | **Settings** > **Appearance** > **Input** | Choose Standard or Classic | +| App icon | **Settings** > **Appearance** > **Icon** | Pick a custom icon (macOS) | +| Font & text | **Settings** > **Appearance** > **Text** | Change font, size, and cursor style | +| Agent autonomy | **Settings** > **Agents** > **Profiles** | Set what the agent can do without asking | +| Default mode | **Settings** > **Agents** > **Warp Agent** > **Input** | Choose whether new tabs open in terminal mode or Agent Mode | + +--- + +## Appearance + +In Warp, navigate to **Settings** > **Appearance** to access these options and control how Warp looks: + +* **[Themes](/terminal/appearance/themes/)** - Choose from pre-loaded themes or create your own [custom theme](/terminal/appearance/custom-themes/) using YAML or a background image. +* **[Prompt chips](/terminal/appearance/prompt/)** - Customize the context chips in your Warp prompt. Right-click the prompt area and select **Edit prompt** to drag and drop chips like directory, git branch, Kubernetes context, and time. +* **[App icons](/terminal/appearance/app-icons/)** - Choose a custom app icon to distinguish Warp in your dock (macOS). +* **[Text, fonts, and cursor](/terminal/appearance/text-fonts-cursor/)** - Change your font type, size, and cursor style. +* **[Input position](/terminal/appearance/input-position/)** - Move your prompt and command line to the top or bottom of the window. +* **[Size, opacity, and blurring](/terminal/appearance/size-opacity-blurring/)** - Adjust window transparency and blur effects. +* **[Pane dimming](/terminal/appearance/pane-dimming/)** - Dim inactive panes to focus on the active one. + +## Layout + +Organize your workspace with tabs, panes, and window configurations. + +* **[Vertical tabs](/terminal/windows/vertical-tabs/)** - Switch to a vertical sidebar layout for tabs, giving you more horizontal space and better visibility when you have many open sessions. +* **[Tabs](/terminal/windows/tabs/)** - Organize sessions into tabs with custom titles and colors. Right-click a tab to pick a color. +* **[Split panes](/terminal/windows/split-panes/)** - Divide any tab into multiple panels, side-by-side or stacked. +* **[Tab configs](/terminal/windows/tab-configs/)** - Save and restore tab layouts with predefined pane arrangements and startup commands. +* **[Global hotkey](/terminal/windows/global-hotkey/)** - Set up a dedicated hotkey window (Quake Mode) that appears and hides with a keyboard shortcut. + +## Input and editor + +Configure how you type and interact with the terminal input. + +* **[Standard vs Classic input](/terminal/input/classic-input/)** - Standard input provides easier access to AI features and is the default for new users. Classic input resembles a traditional terminal prompt. Switch between them in **Settings** > **Appearance** > **Input**. +* **[Keyboard shortcuts](/getting-started/keyboard-shortcuts/)** - Warp supports common shortcuts and lets you create custom ones. Manage them from **Settings** > **Keyboard shortcuts**, or import keybindings from another terminal during [migration](/getting-started/migrate-to-warp/). +* **[Vim keybindings](/terminal/editor/vim/)** - Enable Vim keybindings for keyboard-driven text editing in the input editor. +* **Tab key behavior** - Configure what `Tab` does in **Settings** > **Features**. Options include accepting autosuggestions or triggering completions. + +## AI and models + +Control how Warp's agents behave and which models they use. + +* **[Model choice](/agent-platform/capabilities/model-choice/)** - Choose your preferred AI model (Claude, GPT, Gemini, or Auto) from the model selector in any agent conversation. +* **[Agent profiles and permissions](/agent-platform/capabilities/agent-profiles-permissions/)** - Configure how much autonomy the agent has: what it can auto-execute, what requires approval, and command allowlists/denylists. +* **Default mode for new sessions** - Choose whether new tabs open in terminal mode or Agent Mode by default. Set this in **Settings** > **Agents** > **Warp Agent** > **Input**. + +## Import and sync + +Bring your existing settings into Warp or keep settings synchronized across machines. + +* **[Migrate from another terminal](/getting-started/migrate-to-warp/)** - Per-source guides for switching to Warp from iTerm2, Ghostty, macOS Terminal, Windows Terminal, VS Code, Cursor, Claude Code, and more. Includes automatic settings import for iTerm2. +* **[Settings sync](/terminal/more-features/settings-sync/)** - Sync your Warp settings across machines (Beta). + +--- + +## Next steps + +Now that Warp looks and feels like yours, the next step is to put it to work on a real project. Open a codebase to unlock context-aware agents, or start an agent conversation to see how terminal commands and AI work together. + +* **[Codebase Context](/agent-platform/capabilities/codebase-context/)** - Open a project and index your codebase so agents give you context-aware answers about your code. +* **[Terminal and Agent modes](/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes/)** - Learn how terminal mode and agent conversations work together. diff --git a/src/content/docs/getting-started/quickstart/installation-and-setup.mdx b/src/content/docs/getting-started/quickstart/installation-and-setup.mdx new file mode 100644 index 0000000..e17b6a2 --- /dev/null +++ b/src/content/docs/getting-started/quickstart/installation-and-setup.mdx @@ -0,0 +1,218 @@ +--- +title: Installation and setup +description: >- + Install Warp on macOS, Windows, or Linux. All installation options include + auto-update for new features, bug fixes, and performance improvements. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +:::note +**Platform support:** Warp is supported on macOS (Intel and Apple silicon), Windows (x86\_64 and ARM64), and Linux (x86\_64 and ARM64). +::: + +## Install Warp + +:::caution +**Visit** [Known Issues](/support-and-community/troubleshooting-and-support/known-issues/) **to get more details on setting up and troubleshooting Warp.** +::: + +<Tabs> + <TabItem label="macOS"> + :::note + **Minimum requirements:** Intel or Apple silicon macOS 10.14 or above and hardware that supports [Metal](https://support.apple.com/en-us/HT205073). + ::: + + **Download Warp and drag into your Applications folder** + + <VideoEmbed url="https://www.warp.dev/download" title="Download Warp" /> + + **Install using Homebrew by running the command below** + + ```bash + brew install --cask warp + ``` + + After installation, you can find Warp in your Applications folder. + </TabItem> + <TabItem label="Windows"> + :::note + **Minimum requirements:** Warp requires Windows 10 version 1809 (build 17763) or later, Windows Server 2019 (build 17763) and Windows Server 2022 (build 20348) or later. This is a requirement for [Windows Pseudo Console (ConPTY)](https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/). + ::: + + **Download Warp, then open and run the installer** + + <VideoEmbed url="https://www.warp.dev/download" title="Download Warp" /> + + **Install using WinGet by running the command below** + + ```powershell + winget install Warp.Warp + ``` + + After installation, you can find Warp in the Start menu. + </TabItem> + <TabItem label="Linux"> + :::note + **Minimum requirements:** Linux distribution with glibc >= 2.31 (released Feb. 2020) and support for _either_ [OpenGL ES 3.0+ or Vulkan](https://github.com/gfx-rs/wgpu?tab=readme-ov-file#supported-platforms). + + This includes (but is not limited to) the following: + + * Ubuntu 20.04 + * Debian 11 ("bullseye") + * Fedora 32 + * Arch Linux + ::: + + **Visit the Warp download page for the full list of Linux installation options** + + <VideoEmbed url="https://www.warp.dev/download" title="Download Warp" /> + + **Debian- and Ubuntu-based distributions** + + The easiest way to install Warp is to download [x64 .deb package](https://app.warp.dev/download?package=deb) or [ARM64 deb package](https://app.warp.dev/download?package=deb_arm64). After downloading, you can install the package with: + + ``` + sudo apt install ./<file>.deb + ``` + + Installing the .deb package will automatically set up the Warp apt repository and signing key needed to automatically update Warp and verify the integrity of the downloaded packages. + + Alternatively, you can manually configure the Warp apt repository and install Warp by running the following commands: + + ``` + sudo apt-get install wget gpg + wget -qO- https://releases.warp.dev/linux/keys/warp.asc | gpg --dearmor > warpdotdev.gpg + sudo install -D -o root -g root -m 644 warpdotdev.gpg /etc/apt/keyrings/warpdotdev.gpg + sudo sh -c 'echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/warpdotdev.gpg] https://releases.warp.dev/linux/deb stable main" > /etc/apt/sources.list.d/warpdotdev.list' + rm warpdotdev.gpg + sudo apt update && sudo apt install warp-terminal + ``` + + **RHEL-, Fedora-, and CentOS-based distributions** + + The easiest way to install Warp is to download the [x64 .rpm package](https://app.warp.dev/download?package=rpm) or [ARM64 .rpm package](https://app.warp.dev/download?package=rpm_arm64). After downloading, you can install the package with: + + ```bash + sudo dnf install ./<file>.rpm + ``` + + Installing the .rpm package will automatically set up the Warp yum repository. On first update, `dnf` will retrieve the signing key needed to verify the integrity of the downloaded packages. + + Alternatively, you can manually configure the Warp yum repository and install Warp by running the following commands: + + ```bash + sudo rpm --import https://releases.warp.dev/linux/keys/warp.asc + sudo sh -c 'echo -e "[warpdotdev]\nname=warpdotdev\nbaseurl=https://releases.warp.dev/linux/rpm/stable\nenabled=1\ngpgcheck=1\ngpgkey=https://releases.warp.dev/linux/keys/warp.asc" > /etc/yum.repos.d/warpdotdev.repo' + sudo dnf install warp-terminal + ``` + + **Arch Linux-based distributions** + + The easiest way to install Warp is to download the [x64 .pkg.tar.zst package](https://app.warp.dev/download?package=pacman) or [ARM64 pacman package](https://app.warp.dev/download?package=pacman_arm64). After downloading, you can install the package with: + + ```bash + sudo pacman -U ./<file>.pkg.tar.zst + ``` + + The first time you update Warp through the app, it will guide you through setting up the Warp pacman repository and signing key. + + Alternatively, you can manually configure the Warp pacman repository and install Warp by running the following commands: + + ```bash + sudo sh -c "echo -e '\n[warpdotdev]\nServer = https://releases.warp.dev/linux/pacman/\$repo/\$arch' >> /etc/pacman.conf" + sudo pacman-key -r "linux-maintainers@warp.dev" + sudo pacman-key --lsign-key "linux-maintainers@warp.dev" + sudo pacman -Sy warp-terminal + ``` + + **OpenSUSE- and SLE-based distributions** + + The Warp yum repository also works for OpenSUSE- and SLE-based systems. Download the [x64 .rpm package](https://app.warp.dev/download?package=rpm) or [ARM64 .rpm package](https://app.warp.dev/download?package=rpm_arm64). After downloading, you can install the package with: + + ```bash + sudo zypper install ./<file>.rpm + ``` + + Installing the .rpm package will automatically set up the Warp yum repository. On first update, `zypper` will retrieve the signing key needed to verify the integrity of the downloaded packages. + + Alternatively, you can manually configure the Warp yum repository and install Warp by running the following commands: + + ```bash + sudo rpm --import https://releases.warp.dev/linux/keys/warp.asc + sudo sh -c 'echo -e "[warpdotdev]\nname=warpdotdev\ntype=rpm-md\nbaseurl=https://releases.warp.dev/linux/rpm/stable\nenabled=1\nautorefresh=1\ngpgcheck=1\ngpgkey=https://releases.warp.dev/linux/keys/warp.asc\nkeeppackages=0" > /etc/zypp/repos.d/warpdotdev.repo' + sudo zypper install warp-terminal + ``` + + **AppImage** + + We also provide an [AppImage](https://appimage.org), a single-file executable version of Warp. Installing Warp via a package manager is recommended, as it will ensure your system has all necessary dependencies installed. + + You can download the Warp AppImage with the following commands: + + ```bash + # On x64 systems + curl -L "https://app.warp.dev/download?package=appimage" -o Warp-x64.AppImage + chmod +x Warp-x64.AppImage + ``` + + ```bash + # On ARM64 systems + curl -L "https://app.warp.dev/download?package=appimage_arm64" -o Warp-ARM64.AppImage + chmod +x Warp-ARM64.AppImage + ``` + + **Running Warp on Linux** + + If you installed a package, find Warp in your desktop manager or run `warp-terminal` on your terminal. If you're using the AppImage, you can launch it by navigating to the directory where the AppImage is located and running `./Warp-*.AppImage`. + </TabItem> +</Tabs> + +:::note +Want to try our newest features? [Warp Preview](/support-and-community/community/warp-preview-and-alpha-program/) is available on all platforms and architectures (macOS, Windows, Linux) for early access to experimental features. +::: + +## Build from source + +Warp's client is open source under [AGPL v3](https://github.com/warpdotdev/warp/blob/master/LICENSE), so you can build it yourself from [`warpdotdev/warp`](https://github.com/warpdotdev/warp). + +Clone the repo, bootstrap toolchain dependencies, and start a development build: + +```bash +git clone https://github.com/warpdotdev/warp.git +cd warp +./script/bootstrap +cargo run +``` + +`cargo run` launches a `warp-oss` binary built from your local checkout. See the repo's `README.md` and `CONTRIBUTING.md` for full prerequisites (Xcode on macOS, the pinned Rust toolchain, `protoc`) and development setup. + +:::note +Use the official builds for daily use. Self-built `warp-oss` binaries use a separate config and data directory, so they run alongside official Warp without conflicting, but they don't auto-update and don't carry the production code-signing identity. Use them for developing, auditing, or contributing back upstream. +::: + +## Initial setup + +### Log in to Warp (Optional) + +After installation, you have the option to create a Warp account through the "Sign up" button (top right), or by navigating to **Settings** > **Account** > **Sign up**. Optionally, you can skip this step. If you're having issues logging in, see the [Login Troubleshooting](/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/) page. + +:::note +If you sign up using Google or GitHub, Warp only gets access to the associated email address. Visit the [Privacy](/support-and-community/privacy-and-security/privacy/) page for more details on Warp's approach to privacy. +::: + +### Use Warp offline + +You will only need an active internet connection when you open the Warp app for the first time. Once opened, [Warp is able to run with no internet connection](/support-and-community/troubleshooting-and-support/using-warp-offline/), although certain features that require an internet connection like AI and real-time collaboration features will be unavailable. + +### Import your settings + +If you are migrating to Warp from another terminal, editor, or AI coding tool, see the [Migrate to Warp](/getting-started/migrate-to-warp/) docs for per-source guides including settings-import steps and feature equivalents. + +### Set up your Warp default shell + +Warp tries to load your login shell by default. Currently, Warp supports bash, fish, zsh, and PowerShell (pwsh). If your login shell is set to something else (for example, Nushell) Warp will load zsh by default. + +Zsh is the default login and interactive shell on macOS (starting with macOS Catalina in 2019), replacing the bash shell. For most Linux distributions, the default shell is bash. + +You can change your default shell by going to **Settings** > **Features** > **Session**. In the Startup shell for new sessions section, you can choose which shell you want Warp to use. diff --git a/src/content/docs/getting-started/supported-shells.mdx b/src/content/docs/getting-started/supported-shells.mdx new file mode 100644 index 0000000..14a05b6 --- /dev/null +++ b/src/content/docs/getting-started/supported-shells.mdx @@ -0,0 +1,174 @@ +--- +title: Supported Shells +description: >- + Warp supports bash, zsh, fish, and PowerShell across macOS, Windows, and + Warp supports bash, zsh, fish, PowerShell, and WSL2 across macOS, Windows, + and Linux. +--- + +## Warp default shell + +Warp tries to load your login shell by default. Currently, Warp supports bash, fish, zsh, and PowerShell (pwsh). If your login shell is set to something else (e.g. Nushell) Warp will show a banner indicating it's not supported and load the default shells listed below: + +* On macOS, zsh is the default shell. +* On Windows, PowerShell (pwsh) is the default shell. +* On Linux, bash is the default shell. + +:::note +If you run into issues configuring your RC files (`~/.bashrc`, `~/.zshrc`, `config.fish`, `Microsoft.PowerShell_profile.ps1`) with Warp, please see [Configuring and debugging your RC files](/support-and-community/troubleshooting-and-support/known-issues/#configuring-and-debugging-your-rc-files). +::: + +### Changing what shell Warp uses + +To change the default shell, we recommend you choose a shell in Warp by going to **Settings** > **Features** and scrolling to the `Session` section, then select the "Startup shell for new sessions" + +:::note +The changes to your shell will only take effect when you start a new session. +::: + +## Customizing your shell environment + +### Customize your zsh shell environment + +Zsh can be customized via the `~/.zshrc` file, which runs whenever a new session starts (window, tab, or pane). Use it to set environment variables, aliases, and customize the [prompt](/terminal/appearance/prompt/). + +#### Editing the .zshrc file + +Edit `~/.zshrc` using `nano ~/.zshrc` or `vi ~/.zshrc`. + +:::note +Files starting with a dot (`.`) are hidden by default. Check your file explorer’s settings to show hidden files. +::: + +#### Reloading the zshrc file + +Apply changes by running `source ~/.zshrc` or restarting Warp/opening a new session. + +### Customize your Bash shell environment + +Bash is pre-installed on macOS and can be customized using `~/.bashrc` (for non-login shells) or `~/.bash_profile` (for login shells). Use these files to set environment variables, aliases, and customize the [prompt](/terminal/appearance/prompt/). + +#### Editing the .bashrc file + +Edit `~/.bashrc` using `nano ~/.bashrc` or `vi ~/.bashrc`. + +#### Reloading the bashrc file + +Apply changes by running `source ~/.bashrc` or restarting Warp/opening a new session. + +:::note +Files starting with a dot (`.`) are hidden by default. Check your file explorer’s settings to show hidden files. +::: + +### Customize your Fish shell environment + +Fish is a user-friendly shell with autosuggestions and syntax highlighting. Its configuration file is `~/.config/fish/config.fish`. + +#### Editing the config.fish file + +Edit `~/.config/fish/config.fish` using `nano ~/.config/fish`. Use it to set environment variables, aliases, and functions. + +#### Reloading the config.fish file + +Apply changes by running `source ~/.config/fish` or restarting Warp/opening a new session. + +:::note +Unlike Bash and Zsh, Fish does not use `export VAR=value`. Use `set -Ux VAR value` for persistent environment variables. +::: + +### Customize your PowerShell shell environment + +PowerShell can be customized via its profile script, located at `$PROFILE`. Check if it exists with `Test-Path $PROFILE`, and create it if needed with `New-Item -Path $PROFILE -ItemType File -Force`. + +#### Editing the PowerShell profile + +Edit the profile using `code $PROFILE`, and use it to set environment variables, aliases, custom prompts, and scripts. + +#### Reloading the PowerShell profile + +Apply changes by restarting Warp or opening a new session. + +:::note +PowerShell’s execution policy may block scripts. Enable profile execution with: + +```powershell +Set-ExecutionPolicy RemoteSigned -Scope CurrentUser +``` +::: + +## Additional shell guidance for macOS + +#### Setting up zsh on Warp + +By default, macOS ships with [zsh](https://zsh.sourceforge.io/Doc/Release/zsh_toc.html) located in `/bin/zsh`. You can confirm this location by typing `which zsh` in Warp. You can also check the version of zsh installed on your system by simply typing the following: + +`$ zsh --version` + +### Using fish shell with Warp on macOS + +#### Step 1: Install fish + +While bash, and zsh come pre-installed on macOS systems, fish shell does not. So before using fish with Warp, you will need to install it. Install fish 3.6 or above using one of the methods listed below - + +1. With Homebrew: If you already have homebrew installed, you can simply type `brew install fish`, and follow the instructions. +2. Download the installer at [fishshell.com](https://fishshell.com/) + +#### Step 2: Switch to fish as the default shell + +Once you’ve installed fish on your computer, you can set it as your default shell, so Warp will use it every time a new tab, pane, or window is opened. You can either make fish the default shell for only Warp, from the session settings (**Settings** > **Features** > **Session**), or for your user account. To change your account's default shell, you need to run two commands. + +**If you used Homebrew to install fish on macOS or if you used the macOS installer** available on fishshell.com to install fish, type the following two commands in Warp: + +``` +echo $(which fish) | sudo tee -a /etc/shells +chsh -s $(which fish) +``` + +:::note +If you prefer, you can also manually edit the `/etc/shells` file using the editor of your choice (you may need sudo privileges). +::: + +:::note +**Why the different locations?** The location of fish depends on how it was installed. Homebrew installs programs under `/usr/local` on macOS with Intel processors, but under `/opt/homebrew` on macOS with Apple Silicon. So, if you used Homebrew to install fish on macOS with Apple Silicon, the location of the executable is - `/opt/homebrew/bin/fish`.\ +You can identify where fish is installed by running `which fish`. +::: + +### Using PowerShell (pwsh) with Warp on macOS + +#### Step 1: Install PowerShell + +While bash, and zsh come pre-installed on macOS systems, PowerShell shell does not. So before using PowerShell with Warp, you will need to install it. Install PowerShell 7.0 or above using one of the methods listed below - + +1. With Homebrew: If you already have homebrew installed, you can simply type `brew install powershell/tap/powershell`, and follow the instructions. +2. Download from the [official Microsoft website](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell). + +#### Step 2: Switch to pwsh as the default shell + +Once you’ve installed PowerShell on your computer, you can set it as your default shell, so Warp will use it every time a new tab, pane, or window is opened. You can either make pwsh the default shell for only Warp, from the session settings (**Settings** > **Features** > **Session**), or for your user account. To change your account's default shell, you need to run two commands. + +``` +echo $(which pwsh) | sudo tee -a /etc/shells +chsh -s $(which pwsh) +``` + +:::note +If you prefer, you can also manually edit the `/etc/shells` file using the editor of your choice (you may need sudo privileges). +::: + +:::note +**Why the different locations?** The location of pwsh depends on how it was installed. Homebrew installs programs under `/usr/local` on macOS with Intel processors, but under `/opt/homebrew` on macOS with Apple Silicon. So, if you used Homebrew to install pwsh on macOS with Apple Silicon, the location of the executable is - `/opt/homebrew/bin/pwsh`. +You can identify where pwsh is installed by running `which pwsh`. +::: + +## Using Warp with shells on Windows + +On Windows, Warp's default shell is PowerShell 7 (pwsh). Warp for Windows supports several shells: + +* PowerShell 7 (default) +* PowerShell 5 +* Windows Subsystem for Linux (WSL2) +* Git Bash + +:::note +Windows Command Prompt (cmd.exe) is not currently supported. For more information and updates about cmd.exe support, please see [this GitHub issue](https://github.com/warpdotdev/Warp/issues/5882). +::: diff --git a/src/content/docs/guides/agent-workflows/how-to-edit-agent-code-in-warp.mdx b/src/content/docs/guides/agent-workflows/how-to-edit-agent-code-in-warp.mdx new file mode 100644 index 0000000..434a7e3 --- /dev/null +++ b/src/content/docs/guides/agent-workflows/how-to-edit-agent-code-in-warp.mdx @@ -0,0 +1,77 @@ +--- +title: "How to: Edit Agent Code in Warp" +description: >- + Review, edit, and refine AI-generated code diffs directly in Warp — accept, + reject, or modify changes before applying them. +sidebar: + label: "Edit Agent code in Warp" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Warp lets you see, edit, and refine AI-generated code diffs directly within the app.\ +This makes debugging and bug-fix workflows fast, transparent, and interactive. + +<VideoEmbed url="https://youtu.be/dm-P63USsVg?si=I7Td4EbtbCD1PJ3l" /> + +--- + +### 1. Starting an Agent Task + +When you start an agent task, Warp: + +1. Uses your prompt and context +2. Builds a task list +3. Searches across your codebase using tools like: + * Grep + * Codebase embeddings + * Semantic search + +Warp shows progress step-by-step, including what it’s searching and which files are being modified. + +--- + +### 2. Reviewing Diffs + +Warp generates diffs for every proposed change.\ +You can: + +* Accept changes +* Refine them with a follow-up prompt (`Cmd + R`) +* Or directly edit the code in the inline editor view + +This editor view works like a lightweight IDE — perfect for quick corrections before applying. + +--- + +### 3. Applying or Skipping Changes + +Once you’re happy with a diff: + +* Click Apply Changes to accept it +* Or Fast-Forward to let Warp automatically continue the rest of the fix sequence + +You can control this level of autonomy globally in Settings → AI → Autonomy. + +--- + +### 4. Compiling and Verifying Fixes + +After applying changes, you can immediately test your build, like: + +```bash +cargo run +``` + +Warp monitors compilation, verifies results, and runs post-checks automatically. + +--- + +### 5. Visual Verification + +In this example, the bug involved a checkbox not being honored in the UI.\ +\ +After the agent’s fix: + +* The checkbox logic now works as intended +* The model picker toggles correctly +* The UI behaves as expected diff --git a/src/content/docs/guides/agent-workflows/how-to-explain-your-codebase-using-warp-rust-codebase.mdx b/src/content/docs/guides/agent-workflows/how-to-explain-your-codebase-using-warp-rust-codebase.mdx new file mode 100644 index 0000000..02b00c8 --- /dev/null +++ b/src/content/docs/guides/agent-workflows/how-to-explain-your-codebase-using-warp-rust-codebase.mdx @@ -0,0 +1,57 @@ +--- +title: "How to: Explain Your Codebase Using Warp (Rust Codebase)" +description: >- + Use Warp's coding agents with semantic and symbol search to explore, + understand, and modify unfamiliar codebases — demonstrated on a large Rust + project. +sidebar: + label: "Explain your codebase using Warp" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +Learn how to use Warp’s AI agent to explore and understand large, unfamiliar codebases — using semantic and symbol-level search. + +<VideoEmbed url="https://www.youtube.com/watch?v=11rz9OYQ8Hg" /> + +--- + +## Overview + +This walkthrough shows: + +* How Warp explains unknown sections of code +* How it combines semantic and keyword searches +* How to use these insights to modify UI components + +--- + +<Steps> + +1. #### Prompt + + ``` + Please explain how the agent popup code is structured, + where it lives in the codebase, + and how it is rendered and called. + I want to understand the full data flow and structure + so I can add a new agent button to it. + ``` + +2. #### How Warp’s Agent Searches + + Warp begins by using **semantic (vectorized) search** to locate relevant files.\ + Once it finds probable matches (e.g., `agent_management_popup.rs`), it switches to **symbolic search** (`grep` and direct code reads). + + Warp intelligently reads large files (splitting them into smaller chunks) to extract relevant definitions and render logic. + +3. #### Generated Explanation + + Warp returns a full breakdown: + + * File paths where the popup is defined + * How it’s rendered within the workspace + * Which actions and UI components trigger it + * A step-by-step view of data flow through the popup component + +</Steps> diff --git a/src/content/docs/guides/agent-workflows/how-to-review-ai-generated-code.mdx b/src/content/docs/guides/agent-workflows/how-to-review-ai-generated-code.mdx new file mode 100644 index 0000000..3cb3020 --- /dev/null +++ b/src/content/docs/guides/agent-workflows/how-to-review-ai-generated-code.mdx @@ -0,0 +1,117 @@ +--- +title: How to review AI-generated code +description: >- + Review AI-generated code in Warp with visual diffs and inline comments — + works with Claude Code, Codex, or any CLI agent. +sidebar: + label: "Review AI-generated code" +--- + +Coding agents can produce hundreds of lines of code in seconds, but shipping that code without review is risky. This guide provides a practical workflow for reviewing agent-generated code in Warp, catching common issues, and giving structured feedback that the agent can act on. Plan on about 10 minutes to complete. + +## Prerequisites + +* **A Git-tracked project** — Code review in Warp works on any Git repository. +* **An AI coding agent** — This workflow applies to any CLI agent: [Claude Code](/guides/external-tools/how-to-set-up-claude-code/), [Codex](/guides/external-tools/how-to-set-up-codex-cli/), OpenCode, or Warp's built-in agent. See [Third-party CLI agents](/agent-platform/cli-agents/overview/) for setup. + +## Why review matters + +AI agents are fast but imperfect. They hallucinate imports, introduce subtle logic errors, make bad architectural decisions, and duplicate code. Reviewing agent output is the step that turns agentic development from vibe coding into a workflow you can trust. + +Common issues in AI-generated code: + +* **Hallucinated imports** — referencing packages or modules that don't exist in your project +* **Redundant logic** — duplicating existing functionality instead of reusing it +* **Questionable architectural decisions** — adding new patterns instead of following existing ones, or restructuring code in ways that conflict with your project's architecture +* **Security gaps** — hardcoded credentials, missing input validation, or overly permissive permissions +* **Style drift** — ignoring your project's conventions for naming, error handling, or file structure +* **Incomplete error handling** — happy-path code that crashes on edge cases + +## 1. Give the agent a task + +Whether you're using Claude Code, Codex, or Warp's built-in agent, start by giving your agent a task. For example: + +``` +Fix the authentication middleware to handle expired tokens gracefully +``` + +The agent will modify one or more files. + +## 2. Open the Code Review panel + +Once the agent has finished the task, open Warp's [Code Review panel](/code/code-review/) to see every file that changed. You can open it in several ways: + +* **Keyboard shortcut**: `⌘+Shift++` (macOS) or `Ctrl+Shift++` (Windows/Linux) +* **Git diff chip**: Click the diff chip in the terminal input that shows files modified and lines changed +* **Review changes button**: After an agent conversation, click **Review changes** at the bottom of the conversation +* **Tab bar**: Click the Code Review button in the top-right corner of Warp + +![Code Review button in the top-right corner of the Warp title bar showing file and line change counts](../../../../assets/guides/code-review-button.png) + +The panel shows all uncommitted changes as a visual diff, grouped by file. Additions are highlighted in green with a `+` prefix, removals in red with a `-` prefix. + +![Code Review panel showing file diffs between branches](../../../../assets/guides/code-review-panel-with-diffs.png) + +## 3. Review diffs by file + +With the Code Review panel, you can review changes file-by-file: + +* **Browse all changed files** using the file sidebar. +* **Switch diff views** to compare against uncommitted changes or against `main`/`master` to see the full scope of what would land in a PR. +* **Click anywhere in the code** to edit diffs directly in the panel. + +Focus on the areas where agents are most likely to make mistakes: imports, error handling, and anything that touches security or authentication. + +![Code Review panel with file navigation sidebar showing changed files](../../../../assets/guides/code-review-file-sidebar.png) + +## 4. Leave inline comments on issues + +Click the "Add comment" button on any line or block of code and add a comment describing what needs to change. Warp anchors each comment to the exact file and line, so any agent understands precisely what to fix. +You can add as many comments as you need before submitting — Warp batches them so the agent receives all your feedback at once instead of processing changes one at a time. + +![Adding an inline comment on a diff line in the Code Review panel](../../../../assets/guides/code-review-inline-comment.png) + +## 5. Submit all comments to the agent + +Once you've reviewed each file and left comments, submit the complete batch. The agent receives all your feedback, applies the requested changes in one pass, and returns an updated diff. + +Review the updated diff to verify the fixes. Repeat this cycle until the code meets your standards: comment, submit, review. + +:::note +This workflow applies to **any CLI agent** running in Warp, not just the built-in agent. You can leave inline comments on diffs generated by Claude Code, Codex, or OpenCode and send them back to the running agent session. +::: + +## 6. Run your project's checks before committing + +Before accepting the changes, run your project's test suite, linter, and type checker. Agent-generated code might pass a visual review but fail automated checks. + +```bash +# Example: run tests and lint +npm test && npm run lint +``` + +If checks fail, you can either fix the issues manually in the Code Review panel or send the error output back to the agent as context for another iteration. + +:::note +**Quick review checklist**: When reviewing agent-generated changes, check that imports resolve, new code doesn't duplicate existing functionality, credentials aren't hardcoded, error handling covers failure cases, style matches your project, tests still pass, and the agent only changed what was asked. +::: + +## Productivity tips + +* **Attach diffs as context** — Select a diff hunk in the Code Review panel and attach it to your next prompt. This grounds the agent's response in your actual code changes. See [Selection as context](/agent-platform/local-agents/agent-context/selection-as-context/) for details. +* **Revert individual hunks** — Don't like one specific change? Revert just that hunk from the Code Review panel without undoing the rest of the agent's work. +* **Compare against main** — Switch the diff view to "Changes vs. main" to see how the agent's work fits into the full scope of your branch, not just the latest edits. +* **Use rules to prevent recurring issues** — If you notice the agent repeatedly making the same mistake (wrong import paths, incorrect naming conventions), add a [Rule](/agent-platform/capabilities/rules/) so it learns your project's standards. + +## Next steps + +You now have a structured workflow for reviewing AI-generated code in Warp: visual diff review, inline comments that feed back to the agent, and batch feedback submission. This workflow works with any CLI coding agent: Claude Code, Codex, OpenCode, or Warp's built-in agent. + +Explore related guides and features: + +* [Set up Claude Code](/guides/external-tools/how-to-set-up-claude-code/) or [Set up Codex CLI](/guides/external-tools/how-to-set-up-codex-cli/) to start using third-party agents in Warp +* [Run multiple agents at once](/guides/agent-workflows/how-to-run-multiple-ai-coding-agents/) to compare outputs from different agents on the same task +* [Claude Code in Warp](https://warp.dev/agents/claude-code) | [Codex in Warp](https://warp.dev/agents/codex) | [Gemini CLI in Warp](https://warp.dev/agents/gemini-cli) | [OpenCode in Warp](https://warp.dev/agents/opencode) — agent-specific overviews on the Warp marketing site +* [Code Review panel](/code/code-review/) — full reference for all Code Review features +* [Interactive Code Review](/agent-platform/local-agents/interactive-code-review/) — detailed docs on inline comments and batch feedback +* [Third-party CLI agents](/agent-platform/cli-agents/overview/) — all supported agents and Warp's universal agent features diff --git a/src/content/docs/guides/agent-workflows/how-to-review-prs-like-a-senior-dev.mdx b/src/content/docs/guides/agent-workflows/how-to-review-prs-like-a-senior-dev.mdx new file mode 100644 index 0000000..ffc49f3 --- /dev/null +++ b/src/content/docs/guides/agent-workflows/how-to-review-prs-like-a-senior-dev.mdx @@ -0,0 +1,98 @@ +--- +title: "How To: Review PRs Like A Senior Dev" +description: >- + Prompt Warp's coding agent to generate structured PR reviews with risk + assessment, critical issues, and merge confidence scoring. +sidebar: + label: "Review PRs like a senior dev" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +Learn how to prompt Warp’s AI to review pull requests like an experienced engineer — focusing on structure, red flags, and clarity + +<VideoEmbed url="https://youtu.be/NVwqQyphlAw?si=zcMR1ZHt-xnIS_ME" /> + +--- + +<Steps> + +1. #### Intro + + This tutorial teaches you how to use Warp to make **pull-request reviews faster and smarter**.\ + Instead of relying on AI summaries, you’ll prompt Warp to generate an **index and priority list**, guiding your review order while flagging risky sections. + + Although this example focuses on large PRs, the same workflow applies to **code reviews**, **design docs**, or **feature diffs**. + +2. #### The Problem + + Large PRs are difficult to parse.\ + AI summaries gloss over nuance and may miss subtle issues — you need structured, prioritized insight instead. + +3. #### The Prompt + + Use this in Warp’s AI input: + + ``` + ## Prompt: Structured PR Review Format + + > Review this pull request and format your response for rapid scanning by a busy maintainer. Follow the structure below. + + --- + + ### 1. 🚨 Risk Assessment + + **Overall Risk:** 🔴 HIGH | 🟠 MEDIUM | 🟢 LOW + **Complexity:** [Simple | Moderate | Complex | Very Complex] + **Blast Radius:** [Isolated | Module-wide | System-wide | External APIs affected] + **Requires Immediate Review:** [YES / NO – why] + + --- + + ### 2. 🔍 Critical Issues + _If none, write “None found” and skip to the next section._ + + #### 1. [CRITICAL ISSUE TITLE] + **File:** `path/to/file.js:L125` + **Impact:** Data loss / Security hole / System crash + **Fix:** + // Quick code fix example here + + --- + + ### 3. ⚠️ Concerns + _Should discuss or fix before merge. If none, write “None found.”_ + + **Examples:** + - [PERFORMANCE] Unindexed query on large table + - [SECURITY] Missing input sanitization in login form + + --- + + ### 4. 🎯 Maintainer Decision Guide + + **Merge confidence:** [0–100]% + - □ Safe to merge after fixing blockers + - □ Needs architecture discussion first + - □ Requires performance testing + - □ Get security team review + - □ Author should split into smaller PRs + + **Time to properly review:** ~[X] minutes + **Recommended reviewer expertise:** [Backend | Security | Database | Frontend] + + --- + + ### 5. 🧭 Formatting Rules + + - Use emoji headers for instant visual recognition + - Keep sections short; if empty, say “None found” + - Blockers get full detail, everything else stays concise + - Include code examples only for blockers + - Bold key impact/risk words + - Use consistent prefixes like [SECURITY], [PERFORMANCE], [LOGIC] for easy scanning + - If PR is genuinely fine, end with: ✅ “This PR is safe to merge as-is.” + + ``` + +</Steps> diff --git a/src/content/docs/guides/agent-workflows/how-to-run-3-agents-in-parallel-summarize-logs-analyze-pr-modify-ui.mdx b/src/content/docs/guides/agent-workflows/how-to-run-3-agents-in-parallel-summarize-logs-analyze-pr-modify-ui.mdx new file mode 100644 index 0000000..c7c339e --- /dev/null +++ b/src/content/docs/guides/agent-workflows/how-to-run-3-agents-in-parallel-summarize-logs-analyze-pr-modify-ui.mdx @@ -0,0 +1,87 @@ +--- +title: "How To: Run 3 Agents in Parallel (Summarize Logs + Analyze PR + Modify UI)" +description: >- + Run three agent tasks simultaneously in Warp — modify UI, analyze code + reviews, and summarize production logs in parallel. +sidebar: + label: "Run 3 agents in parallel" +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +:::note +This educational module demonstrates Warp’s multi‑threading features — running coding, debugging, and analysis tasks simultaneously in multiple agent tabs. +::: + +<VideoEmbed url="https://youtu.be/3jwus1bfKv4" /> + +--- + +### 🧠 Overview + +Warp allows you to launch several agents at once, each focused on a separate task.\ +In the demo, we run three parallel workflows: + +* Modify UI behavior +* Analyze team code reviews +* Summarize logs from production + +<Steps> + +1. #### Launch Agents in Parallel + + Each agent runs in its own tab. + + <Tabs> + <TabItem label="UI Fix"> + Remove the background and border from unfocused input panes. + + ``` + I'd like to make a coding change. Please create a new branch to do this. + + What i want to do is for the Universal Developer Input, remove the border and background if it's being rendered in the same pane that is not focused. Please look at the reference file and at the attached screenshot. In the screenshot, you'll see what it looks like right now - there are two equally prominent input areas, even though one is focused and one is not. What I want to do is make the non-focused one not have a border and not have a background. + + Please check out this linear issue for more information. Also, give me a plan before you make any changes. + ``` + </TabItem> + <TabItem label="Code Review Check"> + Analyze how many pull requests a team member has assigned. + + ``` + Use the Github CLI tool to summarize all open PRs for review that are assigned to user. I'd like to see who is the author of the PR, when was it opened, how long has it been open for, which repo is it in, are there open an dunaddressed commens on it, and is it ready for review? + ``` + </TabItem> + <TabItem label="Log Analysis"> + Summarize Cloud Run logs by error severity. + + ``` + Use the gcloud tool to list all my open projects. Once you've done that, let me select a project. Once I've selected a project, we will want to see all the Cloud Run instances that are available. Then once I've picked a Cloud Run instance, I'd like to get a sumary of the last 2000 logs from that Cloud Run instance to see the history histogram of different types of logging on info, warning, and error levels. + ``` + </TabItem> + </Tabs> + +2. #### Monitor All Agents + + The **task pane** in Warp shows all running agents.\ + You can view plans, progress, and results live without interrupting other tasks. + +3. #### Review Results + + * **Coding Agent:** Implements UI fixes accurately. + * **Code Review Agent:** Reports 26 open PRs (identifies bottlenecks). + * **Log Agent:** Analyzes 1,000 log entries, categorizing errors and flagging Gemini API issues. + +4. #### Why This Matters + + Warp multi‑agent execution allows you to: + + * Run multiple tasks without context switching. + * Keep coding, debugging, and ops visible simultaneously. + * Use AI assistants collaboratively for faster iteration. + + :::tip + Multi‑agent workflows let you debug, code, and analyze in parallel — boosting throughput without leaving the terminal. + ::: + +</Steps> diff --git a/src/content/docs/guides/agent-workflows/how-to-run-multiple-ai-coding-agents.mdx b/src/content/docs/guides/agent-workflows/how-to-run-multiple-ai-coding-agents.mdx new file mode 100644 index 0000000..ce808ae --- /dev/null +++ b/src/content/docs/guides/agent-workflows/how-to-run-multiple-ai-coding-agents.mdx @@ -0,0 +1,150 @@ +--- +title: How to run multiple AI coding agents +description: >- + Run Claude Code, Codex, and other AI coding agents in parallel using + vertical tabs, tab configs, and notifications to manage multiple sessions at + once. +sidebar: + label: "Run multiple AI coding agents" +--- + +Different agents have different strengths. Claude Code might handle refactoring well while Codex might excel at test generation. Instead of choosing one, you can run them in parallel. Assign different tasks to different agents, compare their outputs on the same problem, or have one agent build while another reviews. This guide shows you how to set up a multi-agent workflow in Warp and manage it effectively. Plan on about 15 minutes. + +## Prerequisites + +* **Any coding agent** — For example, Warp's built-in agent, [Claude Code](/guides/external-tools/how-to-set-up-claude-code/), or [Codex CLI](/guides/external-tools/how-to-set-up-codex-cli/). Any combination of supported agents works well: Oz by Warp, Claude Code, Codex, OpenCode, Gemini CLI, Amp, Pi, Droid, and others. +* **A Git-tracked project** — Notifications and code review work best in a Git repository. + +## 1. Switch to vertical tabs + +Vertical tabs are the foundation of a multi-agent workflow. Unlike horizontal tabs, they show rich metadata for each session: which agent is running, which branch you're on, which directory, and the current status. + +To enable vertical tabs: +1. In the Warp app, go to **Settings** > **Appearance** > **Tabs**. +2. Select **Use vertical tab layout**. + +You can configure what information to display for each tab: +* The running agent (Oz, Claude Code, Codex, etc.) +* The current Git branch +* The working directory +* A status indicator showing whether the agent is active, waiting for input, or idle + +![Warp vertical tabs sidebar showing multiple terminal sessions with branch metadata](../../../../assets/terminal/vertical-tabs-multi-agent.png) + +## 2. Launch agents in separate tabs + +Open a new tab for each agent session. Within each tab, navigate to your project directory and start an agent: + +**Tab 1 — Claude Code:** + +```bash +cd ~/your-project +claude +``` + +**Tab 2 — Codex:** + +```bash +cd ~/your-project +codex +``` + +Give each agent a different task, or give them the same task to compare approaches: + +``` +# Claude Code: refactor the authentication module +Refactor src/auth/ to use async/await instead of callbacks + +# Codex: write tests for the same module +Write comprehensive tests for src/auth/ covering edge cases +``` + +![Multiple agent tabs in Warp's vertical sidebar showing session status, branch, and directory metadata](../../../../assets/terminal/multi-agents.png) + +## 3. Monitor agents with notifications + +When you have multiple agents running, you don't need to watch each tab. Warp sends notifications when an agent needs your attention, for example, when it needs permission to run a command or approval to apply a code diff. + +Look for the attention-needed indicator on the tab in the vertical sidebar. Click the tab to jump directly to the agent that needs input. + +Notification setup varies by agent: + +* **Claude Code** — Install the [Warp notification plugin](https://github.com/warpdotdev/claude-code-warp). Warp shows a one-click install chip when you first run Claude Code, or you can install manually. See the [Claude Code guide](/guides/external-tools/how-to-set-up-claude-code/) for details. +* **Codex** — Warp automatically sets up notifications when you first run Codex. No manual setup required. +* **OpenCode** — Add the [Warp notification plugin](https://github.com/warpdotdev/opencode-warp) to your `opencode.json` configuration. + +:::note +Agent notifications are currently supported for Claude Code, Codex, and OpenCode. For setup details, see [Agent notifications](/agent-platform/capabilities/agent-notifications/). For a full breakdown of which features work with each agent, see the [third-party CLI agents feature matrix](/agent-platform/cli-agents/overview/). +::: + +![Warp notification popup showing an agent requesting permission to edit a file](../../../../assets/guides/tab-notification-indicator.png) + +## 4. Compare outputs from different agents + +A practical use of parallel agents is running the same task in different Git worktrees, with different agents, to compare their approaches. For example, prompt both Claude Code and Codex with the following: + +``` +Optimize the database query in src/api/users.ts to reduce response time +``` + +After both agents complete, open the [Code Review panel](/code/code-review/) (`⌘+Shift++`) in each tab to compare their diffs side-by-side. You might find one agent produces cleaner code while the other catches an edge case the first missed. + +## 5. Save your workspace with tab configs + +If you regularly work with the same multi-agent setup, save it as a tab config so you can recreate it with one click: + +1. Hover over the tab and click the three dots on the right-hand side. +2. Click **Save as new config**. + +![Creating a new tab config from the tab context menu in Warp](../../../../assets/terminal/save-new-tab-config.png) + +Tab configs are TOML files that define the directory, startup commands, and layout for a tab. For example, you might create a config that: + +* Opens two panes side-by-side +* Drops you into your project repo automatically +* Starts Claude Code in one pane and Codex in the other + +:::note +Tab configs pair well with [Git worktrees](/code/git-worktrees/). Create a worktree for each agent so they work on isolated branches, then merge the best results. +::: + +## 6. Use Git worktrees for isolated agent workspaces + +When multiple agents modify the same files, they can create conflicts. Git worktrees solve this by giving each agent its own copy of your repo on a separate branch. + +Create worktrees for each agent: + +```bash +git worktree add ../your-project-claude feature/claude-refactor +git worktree add ../your-project-codex feature/codex-refactor +``` + +Then point each agent tab at its own worktree directory. Tab configs complement this workflow. Define each worktree directory and agent startup command in a config, then recreate the full setup with one click. + +After both agents finish, compare the branches and merge the best results: + +```bash +git diff feature/claude-refactor..feature/codex-refactor +``` + +## Productivity tips + +* **Use the Agent Management Panel** — Open the Agent Management Panel to see all active agents across tabs. This gives you a dashboard view of what's running, what's waiting, and what's finished. +* **Color-code your tabs** — Assign different themes or colors to agent tabs so you can visually distinguish them at a glance in the vertical sidebar. +* **Compose with `Ctrl+G`** — Use Warp's rich input editor (`Ctrl+G`) when composing prompts for third-party agents. This gives you click-to-edit instead of arrow-key navigation in the raw CLI. +* **Review all changes before committing** — After running multiple agents, open the Code Review panel to see the combined diff across all files. Use "Changes vs. main" view to see the full scope of all agent-generated changes on your branch. + +## Next steps + +You set up a multi-agent workspace with vertical tabs, launched different agents in parallel, monitored them with notifications, compared their outputs, and learned how to use tab configs and Git worktrees for isolated, reproducible multi-agent workflows. + +Explore related guides and features: + +* [How to review AI-generated code](/guides/agent-workflows/how-to-review-ai-generated-code/) — review and refine the code your agents produced +* [Set up Claude Code](/guides/external-tools/how-to-set-up-claude-code/) or [Set up Codex CLI](/guides/external-tools/how-to-set-up-codex-cli/) if you haven't installed both yet +* [Claude Code in Warp](https://warp.dev/agents/claude-code) — overview of Claude Code support in Warp +* [Codex in Warp](https://warp.dev/agents/codex) — overview of Codex support in Warp +* [Gemini CLI in Warp](https://warp.dev/agents/gemini-cli) — overview of Gemini CLI support in Warp +* [OpenCode in Warp](https://warp.dev/agents/opencode) — overview of OpenCode support in Warp +* [Third-party CLI agents](/agent-platform/cli-agents/overview/) — all supported agents and universal agent features +* [Vertical tabs](/terminal/windows/vertical-tabs/) — full reference for tab features diff --git a/src/content/docs/guides/agent-workflows/how-to-use-voice-and-images-to-prompt-coding-agents.mdx b/src/content/docs/guides/agent-workflows/how-to-use-voice-and-images-to-prompt-coding-agents.mdx new file mode 100644 index 0000000..73eac82 --- /dev/null +++ b/src/content/docs/guides/agent-workflows/how-to-use-voice-and-images-to-prompt-coding-agents.mdx @@ -0,0 +1,111 @@ +--- +title: How to use voice and images to prompt coding agents +description: >- + Use voice and image context to prompt coding agents faster in Warp — works + with Claude Code, Codex, and any CLI agent. +sidebar: + label: "Use voice and images to prompt coding agents" +--- + +Typing detailed prompts for coding agents can be slow. Describing a bug from a screenshot, dictating a complex refactoring plan, or explaining a UI change from a design mockup are examples of tasks that are faster with voice and images than with text alone. This guide shows you how to use multimodal input with any CLI coding agent running in Warp in about 5 minutes. + +## Prerequisites + +* **Warp** — Voice and image input are built into Warp's agent interface. Download from [warp.dev](https://warp.dev). +* **A CLI coding agent** — Voice and image input work with any supported agent: [Claude Code](/guides/external-tools/how-to-set-up-claude-code/), [Codex CLI](/guides/external-tools/how-to-set-up-codex-cli/), OpenCode, Gemini CLI, Amp, or Droid. See [Third-party CLI agents](/agent-platform/cli-agents/overview/) for the full list. +* **A working microphone** (for voice) — Built-in or external, including Bluetooth audio devices. + +## 1. Enable voice input + +Voice transcription is available in Warp's agent input. To use it: + +1. Click the **microphone icon** in the input area, or use the voice input keyboard shortcut. + +![Warp input area showing the microphone icon for voice transcription](../../../../assets/guides/voice-input-microphone.png) + +2. Speak your prompt naturally. Warp transcribes your speech and places the text in the input field. +3. Review the transcription, edit if needed, then submit your prompt. + +Voice input works for both Warp's built-in agent and third-party CLI agents when the agent utility bar is active. + +:::note +You can configure the voice input keybinding in the Warp app under **Settings** > **Agents** > **Warp Agent** > **Voice**. The default uses the `fn` key. +::: + +## 2. Prompt with voice instead of typing + +Voice is fastest for prompts that are easy to say but tedious to type, such as complex descriptions, multi-step plans, or explanations that reference what you're looking at. + +Try prompts like: + +``` +Refactor the authentication middleware to handle three cases: +valid token, expired token, and missing token. For expired tokens, +return a 401 with a refresh token hint. For missing tokens, return +a 403. Add unit tests for each case. +``` + +The transcription appears in your input field where you can review and edit before submitting. + +## 3. Attach screenshots as context + +Paste (`⌘+V`) or drag images directly into the input area to give the agent visual context. This is useful for: + +* **Bug reports** — Screenshot the error in your browser and ask the agent to fix it. +* **Design mockups** — Paste a Figma screenshot and ask the agent to implement the UI. +* **Error messages** — Screenshot a stack trace instead of copying and reformatting it. +* **Visual diffs** — Show the agent what the UI looks like now vs. what it should look like. + +![Image attached as context in the Warp input area alongside a text prompt](../../../../assets/guides/image-as-context.png) + +## 4. Combine voice and images for design-to-code workflows + +The most powerful use of multimodal input is combining voice and images. For example: + +1. Take a screenshot of a design mockup from Figma. +2. Paste it into the input area. +3. Use voice to describe what you want: + +``` +This is the login page design. Implement it using React and Tailwind. +Match the spacing and colors exactly. The form should validate email +format on blur and show inline error messages. +``` + +The agent sees the design and hears your implementation requirements at the same time — much faster than writing a detailed specification by hand. + +## 5. Use voice and images with third-party agents + +Voice and image input work with any CLI agent that Warp detects, not just the built-in agent. When you run Claude Code, Codex, or another supported agent, Warp shows the **agent utility bar** with controls for voice, images, and files. + +To use with a third-party agent: + +1. Start the agent in your terminal (e.g., `claude` or `codex`). +2. The agent utility bar appears automatically when Warp detects the agent session. +3. Use the microphone icon for voice input or paste images as context. +4. Press `Ctrl+G` to open the rich input editor for composing complex prompts with attached images. + +The voice transcription and image context are sent to the running agent session just as if you had typed and pasted them manually. + +:::note +If you don't see the utility bar, make sure you're on the latest Warp version and that the agent is running inside Warp (not an external terminal). +::: + +## Productivity tips + +* **Use voice for code review feedback** — Instead of typing inline comments, use voice to describe what needs to change while looking at the diff in the [Code Review panel](/code/code-review/). +* **Screenshot UI issues** — When you want to change a UI component, just screenshot it, send it to the agent, and describe what you want changed. +* **Dictate commit messages** — After reviewing your changes, use voice to describe what you did. The agent can format it as a proper commit message. +* **Use with Rules for consistent results** — Combine image context with [Rules](/agent-platform/capabilities/rules/) that define your project's UI patterns. The agent will match the mockup while following your existing design system. + +## Next steps + +You can now prompt coding agents using voice transcription and image context — whether you're using Claude Code, Codex, or any other CLI agent in Warp. Voice and images make complex prompts faster to create and more accurate, especially for design-to-code workflows, bug reproduction, and multi-step refactoring plans. + +Explore related guides and features: +* [Set up Claude Code](/guides/external-tools/how-to-set-up-claude-code/) or [Set up Codex CLI](/guides/external-tools/how-to-set-up-codex-cli/) to start using third-party agents +* [How to review AI-generated code](/guides/agent-workflows/how-to-review-ai-generated-code/) — review the code your agents produce +* [Run multiple agents at once](/guides/agent-workflows/how-to-run-multiple-ai-coding-agents/) — combine voice/image prompting with parallel agents +* [Voice input](/agent-platform/local-agents/interacting-with-agents/voice/) — full reference for voice features +* [Images as context](/agent-platform/local-agents/agent-context/images-as-context/) — full reference for image input +* [Third-party CLI agents](/agent-platform/cli-agents/overview/) — all supported agents and universal features diff --git a/src/content/docs/guides/agent-workflows/running-multiple-agents-at-once-with-warp.mdx b/src/content/docs/guides/agent-workflows/running-multiple-agents-at-once-with-warp.mdx new file mode 100644 index 0000000..cce8860 --- /dev/null +++ b/src/content/docs/guides/agent-workflows/running-multiple-agents-at-once-with-warp.mdx @@ -0,0 +1,94 @@ +--- +title: Running Multiple Agents At Once With Warp +description: >- + Run multiple agent tasks simultaneously in Warp — revert PRs, edit + shortcuts, and add tests across repos without losing context. +sidebar: + label: "Run multiple agents at once" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +<VideoEmbed url="https://youtu.be/w0bJFC0u0pE?si=XdP88cSCMXTK6Ec5" /> + +### 1. Why Multiple Agents Matter + +Sometimes you need to work on several coding tasks at once — fix a PR, add a feature, debug a build — without losing context.\ +\ +Warp lets you run multiple agent tasks simultaneously, all within one workspace. + +--- + +### 2. How It Works + +Each agent runs in its own thread, complete with: + +* Progress tracking +* Notifications when blocked or completed +* Separate command histories + +Because Warp is a desktop app, it can send system notifications to alert you when an agent finishes or when it needs review. + +--- + +### 3. Example: Reverting a PR and Editing a Shortcut + +Ben uses voice mode to quickly start tasks. + +Prompt Example:\ +“Find the PR where we added the keyboard shortcut to the UDI input and revert it.” + +He pastes in the PR number, and the agent: + +* Locates the relevant diff +* Reverts the change automatically +* Pushes it to the correct branch + +Warp notifies him when the task completes. + +Then, he runs another prompt: + +Prompt Example:\ +“Change the keyboard shortcut to `Cmd + Shift + I`.” + +Warp modifies `input.rs`, previews the diff, and Ben applies the change directly from Warp. + +--- + +### 4. Managing Multiple Tasks + +You can switch between concurrent agents: + +* Each task appears in a Task List panel +* Completed, canceled, and running tasks are color-coded +* Toast notifications appear when tasks are blocked + +You can even fast-forward agents to auto-approve all code diffs once you trust their trajectory. + +--- + +### 5. Parallel Contexts + +In another repo, Ben adds a new Eval test via a different agent: + +Prompt Example:\ +“Create a Python hello world function and verify it prints ‘Hello World.’” + +Warp’s second agent: + +* Locates the correct file +* Writes the test code +* Verifies execution + +Meanwhile, the first agent continues working on the keyboard shortcut task. + +--- + +### 6. Reviewing All Active Agents + +Open the Agent Mode Dashboard to see: + +* Active tasks +* Completed tasks +* Logs and outputs + +You can refine or cancel tasks mid-run if needed, or switch back to manual commands. diff --git a/src/content/docs/guides/agent-workflows/understanding-your-codebase.mdx b/src/content/docs/guides/agent-workflows/understanding-your-codebase.mdx new file mode 100644 index 0000000..ffbaa5c --- /dev/null +++ b/src/content/docs/guides/agent-workflows/understanding-your-codebase.mdx @@ -0,0 +1,78 @@ +--- +title: Understanding Your Codebase +description: >- + Use Warp's Codebase Context to search across client and server repos, + generate architecture summaries, and onboard to unfamiliar features fast. +sidebar: + label: "Understand your codebase" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +<VideoEmbed url="https://www.youtube.com/watch?v=pohnoRZas-E" /> + +### 1. The Challenge + +Kevin, who worked on Warp’s Windows and Linux builds, wanted to jump into a feature he hadn’t touched before: Block Sharing.\ +\ +This feature spans two codebases — Warp’s client (Rust) and server (Go) — making onboarding tough. + +That’s where Codebase Context comes in. + +--- + +### 2. What Is Codebase Context? + +Warp’s Codebase Context uses semantic search to understand your code.\ +It doesn’t rely on exact function or variable names — instead, it searches based on meaning. + +You can use it through a shared workflow in Warp Drive. + +This prompt tells Warp to: + +* Search across both client and server codebases +* Summarize how a feature works end-to-end +* Include clickable links to relevant files + +--- + +### 3. Real Example: Block Sharing + +Kevin types `block sharing` into Warp’s shared workflow.\ +Warp: + +1. Searches the client codebase for the rendering logic +2. Searches the server codebase for GraphQL handlers +3. Generates a summary combining both perspectives + +The output includes: + +* Architecture overview +* Linked file paths +* Function and module summaries + +No more manual onboarding or guessing file names. + +--- + +### 4. Incremental Syncing + +Whenever you change a file in an indexed repo: + +* Warp detects the update automatically +* Re-embeds just that file +* Keeps your code context fresh + +That means agents never reference stale code. + +--- + +### 5. Why It’s Game-Changing + +Codebase Context helps teams: + +* Understand large or unfamiliar codebases +* Onboard faster +* Jump between client and server logic seamlessly +* Generate accurate, clickable documentation + +> “This saved us hours of one-on-one walkthroughs.” — Lucy diff --git a/src/content/docs/guides/agent-workflows/using-images-as-context-with-warp.mdx b/src/content/docs/guides/agent-workflows/using-images-as-context-with-warp.mdx new file mode 100644 index 0000000..82dbb86 --- /dev/null +++ b/src/content/docs/guides/agent-workflows/using-images-as-context-with-warp.mdx @@ -0,0 +1,94 @@ +--- +title: Using Images As Context With Warp +description: >- + Attach screenshots and design mockups as context for Warp's agent to + generate UI code, debug visual issues, and match Figma designs. +sidebar: + label: "Use images as context" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +<VideoEmbed url="https://youtu.be/_Pc7bL0zAoM?si=v7-0svwdNgv9t-Se" /> + +### 1. Why Images Matter + +Humans process visuals much faster than text — and the same applies to AI.\ +\ +When you’re trying to explain a UI issue (“this button is off by a few pixels”), describing it with words can be clunky.\ +\ +That’s why Warp supports images as context — letting you attach screenshots directly to your prompts. + +> 🧠 “An image is worth a thousand words” — especially when debugging UI or building frontend components. + +--- + +### 2. What Image Context Does + +Image Context allows you to: + +* Attach one or more screenshots to an agent query +* Give visual references for bugs, designs, or features +* Let the agent visually interpret what you mean + +This is especially useful for frontend tasks like: + +* Rebuilding a design from Figma +* Identifying layout misalignments +* Debugging visual bugs + +--- + +### 3. Building an MCP Marketplace from Figma + +Taking a Figma mock of an MCP Server Marketplace and using it as input for Warp. + +#### Step 1. Capture the Mock + +Take a screenshot of your design (e.g., the MCP Marketplace layout). + +#### Step 2. Attach the Image + +In Warp: + +1. Click the 📎 image icon in the input bar +2. Select your screenshot +3. Confirm it’s attached to the query + +--- + +### 4. Running the Task + +Once attached, Warp’s agent: + +1. Detects the attached image +2. Searches your repo (e.g., `collection.rs`) +3. Generates diffs that recreate the UI from the mock +4. Creates corresponding components and layout logic + +You can view and edit these diffs in the Code Diff Viewer, similar to GitHub’s diff interface. + +> 💡 Warp recommends smaller, focused diffs — agents perform better when working iteratively. + +--- + +### 5. Reviewing the Results + +The agent built: + +* A UI component for the MCP Marketplace +* Static data for three MCP servers (`Linear`, `GitHub`, `Stripe`) +* Proper rendering logic and styling + + Verify the UI in Warp: + +> “It matched the mock almost perfectly — something that would’ve taken me two days was done in 20 minutes.” + +--- + +### 6. Optimizing for Performance + +Because images can consume tokens quickly, Warp automatically: + +* Resizes images client-side +* Compresses them intelligently before sending +* Minimizes token usage without losing clarity diff --git a/src/content/docs/guides/agent-workflows/warp-for-product-managers.mdx b/src/content/docs/guides/agent-workflows/warp-for-product-managers.mdx new file mode 100644 index 0000000..bac5158 --- /dev/null +++ b/src/content/docs/guides/agent-workflows/warp-for-product-managers.mdx @@ -0,0 +1,139 @@ +--- +title: "5 AI agent workflows for product managers" +description: >- + Five agent workflows that automate status updates, documentation, Slack search, + and meeting prep for product managers. +--- +Most PM work breaks down into three activities: gathering information, synthesizing it, and communicating the result. These five workflows use Warp's agents and MCP integrations to automate the gathering and speed up the synthesis, so you spend less time switching between tools and more time making decisions. Each workflow takes 5–10 minutes to set up. + +## Prerequisites + +* **Warp** — installed and signed in. See [Installation and setup](/getting-started/quickstart/installation-and-setup/) to get started. +* **MCP servers (optional but recommended)** — Slack, Linear, and Notion all have documented MCP configs in Warp. See [MCP](https://docs.warp.dev/agent-platform/capabilities/mcp/) for setup instructions. Each workflow below notes which MCP servers it uses and includes a fallback for users without MCP. + +:::note +These workflows work with Warp's built-in agent or any third-party CLI agent running in Warp, including Claude Code, Codex, OpenCode, and Gemini CLI. See [Third-party CLI agents](https://docs.warp.dev/agent-platform/cli-agents/overview/) for the full list. +::: + +## 1. Pull cross-project status updates + +Compiling a status update across multiple projects usually means opening Slack, Linear, Notion, and email in separate tabs, reading through each one, and manually synthesizing a summary. With MCP-connected agents, you can pull context from all of these tools in a single prompt. + +1. Tell the agent which projects, tools, and time range to cover. Be specific about the audience and format you need. +2. Submit a prompt that queries your connected tools. For example: + +``` +Pull updates from the last week across #project-atlas and #project-beacon +in Slack, any Linear tickets that moved to Done or In Review, and the +latest entries in our Notion launch tracker. Summarize into a status +update for my skip-level, organized by project. Use bullet points. Flag +anything blocked or at risk. +``` + +3. Review the output and iterate. Ask the agent to adjust the tone (more concise, more formal), reorder sections, or add context for a specific stakeholder. + +The result is a formatted status update ready to paste into Slack or email. + +**MCP servers used** — Slack, Linear, Notion. + +:::note +**Without MCP**: Copy relevant updates from each tool and paste them into your prompt. Ask the agent to synthesize and format the summary. The workflow is the same; MCP just automates the gathering step. +::: + +## 2. Draft documents from the terminal + +Writing a rollout doc, product brief, or strategy doc usually starts with a blank page in Google Docs or Notion. Instead, describe what you need to the agent and iterate on a draft without leaving Warp. + +1. Describe the document type, audience, and structure. For example: + +``` +Draft a product brief for a new onboarding flow redesign. The audience +is engineering and design leads. Include sections for problem statement, +proposed solution, success metrics, and open questions. The problem is +that 40% of new users drop off before completing setup. +``` + +2. Review the draft and iterate. Ask the agent to expand a section, tighten the language, add a competitor comparison, or restructure the outline. +3. Copy the finished draft into Google Docs, Notion, Confluence, or wherever your team keeps docs. If you have Notion MCP connected, ask the agent to push the content directly. + +The result is a structured first draft, grounded in your specific context, ready for review. + +**MCP servers used** — Notion (optional, for pushing content directly). + +:::note +**Without MCP**: Copy the finished draft and paste it into your docs tool manually. +::: + +## 3. Search Slack for meeting prep + +Before a meeting or project check-in, you often need to catch up on activity across multiple Slack channels. Manually reading through 10+ channels is slow. With the Slack MCP server, you can search and summarize in one prompt. + +1. Tell the agent which channels and time range to search. For example: + +``` +Search #eng-backend, #design-reviews, #project-atlas, and +#incidents for the last 3 days. Summarize the key decisions, +open questions, and anything that was escalated. I have a +project sync in 30 minutes and need to be caught up. +``` + +2. Review the structured summary the agent returns, grouped by topic or channel. +3. Ask follow-up questions to drill into specific threads. For example: "What was the resolution on the API rate limiting discussion in #eng-backend?" + +The result is a briefing doc summarizing recent activity across channels, ready in minutes. + +**MCP servers used** — Slack. + +:::note +**Without MCP**: Copy key messages or thread summaries from Slack and paste them into your prompt. Ask the agent to organize and summarize. This works well for a smaller number of channels. +::: + +## 4. Run parallel workstreams in tabs + +PM work often involves juggling multiple threads at once: researching a competitor while drafting a brief while reviewing a doc from a teammate. Warp's vertical tabs let you run separate agent sessions side by side, each focused on a different task. + +1. To enable vertical tabs, in the Warp app go to **Settings** > **Appearance** > **Tabs** and toggle on **Use vertical tab layout**. +2. Open a separate tab for each workstream. For example: + * **Tab 1** — researching competitor pricing via web search + * **Tab 2** — drafting a product brief based on the research + * **Tab 3** — summarizing Slack threads for a stakeholder update +3. Each tab shows which agent is running and its current status. Warp sends notifications when an agent needs your input, so you don't need to watch each tab. + +This "thought threads" pattern keeps your workstreams isolated and lets you context-switch without losing progress. For a deeper walkthrough of multi-agent tab setups, including tab configs and Git worktrees, see [Run multiple AI coding agents](/guides/agent-workflows/how-to-run-multiple-ai-coding-agents/). + +## 5. Use voice to draft strategy docs + +When thinking through a brief, strategy doc, or stakeholder update, talking is often faster than typing. Warp's voice input lets you dictate a rough draft, then ask the agent to clean it up. + +1. Click the **microphone icon** in the input area or press the voice input key (default: `fn` key) to start recording. +2. Talk through your document naturally. Describe the problem, your proposed approach, open questions, and next steps. Don't worry about structure or polish. +3. After the transcription appears, submit a follow-up prompt: + +``` +Clean up that transcription into a structured strategy doc. Add an +executive summary at the top, organize the body into Problem, Approach, +Risks, and Next Steps sections, and tighten the language for a +leadership audience. +``` + +The result is a structured first draft from a stream-of-consciousness recording. For full setup details and more use cases, see [Use voice and images to prompt agents](/guides/agent-workflows/how-to-use-voice-and-images-to-prompt-coding-agents/). + +## Productivity tips + +* **Save Rules for recurring formats** — Save a Rule with your team's status update format, doc templates, or project list so agents start with the right context every time. See [Rules](https://docs.warp.dev/agent-platform/capabilities/rules/). +* **Create Saved Prompts for recurring workflows** — Turn your weekly status prompt or meeting prep prompt into a reusable Saved Prompt so you can run it with one click. See [Trigger reusable actions with Saved Prompts](/guides/configuration/trigger-reusable-actions-with-saved-prompts/). +* **Use `Ctrl+G` for complex prompts** — Open the rich input editor for click-to-edit prompt composition instead of navigating with arrow keys. Works with any CLI agent running in Warp. See [Rich Input Editor](https://docs.warp.dev/agent-platform/cli-agents/rich-input/). +* **Save tab configs for recurring setups** — If you regularly run a research + drafting + review tab layout, save it as a tab config for one-click workspace setup. See [Tab Configs](https://docs.warp.dev/terminal/windows/tab-configs/). + +## Next steps + +You now have five workflows for automating the information gathering, synthesis, and communication that make up most PM work: cross-project status updates, document drafting, Slack search for meeting prep, parallel workstreams in tabs, and voice-to-text for rough drafts. + +To go deeper on any of the tools used in these workflows, explore the related guides below. You can also customize how agents behave across your team with Rules, Saved Prompts, and MCP integrations. + +* [Connect agents to MCP servers](/guides/external-tools/using-mcp-servers-with-warp/) — set up Slack, Linear, Notion, and other MCP integrations +* [Use voice and images to prompt agents](/guides/agent-workflows/how-to-use-voice-and-images-to-prompt-coding-agents/) — full setup and use cases for multimodal input +* [Run multiple AI coding agents](/guides/agent-workflows/how-to-run-multiple-ai-coding-agents/) — multi-tab workflows, tab configs, and Git worktrees +* [MCP](https://docs.warp.dev/agent-platform/capabilities/mcp/) — full reference for MCP server configuration +* [Rules](https://docs.warp.dev/agent-platform/capabilities/rules/) — save persistent context so agents follow your team's conventions +* [Voice input](/agent-platform/local-agents/interacting-with-agents/voice/) — full reference for voice transcription features diff --git a/src/content/docs/guides/agent-workflows/warp-vs-claude-code.mdx b/src/content/docs/guides/agent-workflows/warp-vs-claude-code.mdx new file mode 100644 index 0000000..97448f8 --- /dev/null +++ b/src/content/docs/guides/agent-workflows/warp-vs-claude-code.mdx @@ -0,0 +1,152 @@ +--- +title: Warp vs Claude Code +description: >- + Compare Warp and Claude Code across setup, diff review, model selection, + configuration, and performance. +# Unlisted: not in the Guides sidebar yet, pending team feedback. The `topic` +# field associates the page with the Guides topic so starlight-sidebar-topics +# can resolve it without listing it under any group. +topic: guides +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +<VideoEmbed url="https://youtu.be/NUVftxAqZQo" /> + +### 1. Overview + +This walkthrough compares Claude Code and Warp’s built-in coding agent — two tools built for AI-assisted development.\ +Both can: + +* Read and edit files +* Generate code diffs +* Plan multi-step tasks\ + \ + But they differ in experience, configurability, and performance. + +--- + +### 2. Setup and Interface + +#### Claude Code + +* Runs as a CLI tool, requiring a terminal and the `claude` CLI installed. +* You type prompts directly into a command box. +* Supports file reading, search, and diff generation. + +#### Warp + +* Built directly into the Warp terminal. +* No installation needed — type a natural-language query or click the Agent button to enter Agent Mode. +* Handles the same operations as Claude Code but integrated into the environment you already use. + +--- + +### 3. Reviewing Diffs + +In Claude Code: + +* You manually review diffs via CLI or external editors like VS Code. +* You can hit Shift + Tab to auto-accept all edits. + +In Warp: + +* You get a visual diff view built in. +* Accept, reject, or manually edit diffs inline using Warp’s lightweight editor. +* The agent automatically updates its context to avoid overwriting your changes. + +--- + +### 4. Planning & Context Gathering + +Both support planning mode for complex tasks: + +* Claude Code uses a Markdown-style plan view. +* Warp can either show a similar plan or skip planning for short tasks. + +For context: + +* Both allow file references with `@filename`. +* Warp extends this with symbol referencing (`@functionName`) and a file tree explorer, letting you pull in specific lines and symbols as context. + +--- + +### 5. Model Selection + +Claude Code lets you pick between Claude 3 models (`Sonnet`, `Opus`, `Haiku`) via the `/model` menu. + +Warp supports multiple ecosystems: + +* Claude (Sonnet, Opus) +* GPT-5 (various reasoning levels) +* Gemini series + +Switch models from the dropdown or directly in the agent menu. + +--- + +### 6. Configuration + +In Claude Code: + +* Everything is configured via `/commands` in the CLI. +* Includes model switching, tool permissions, and sub-agent creation. + +In Warp: + +* Configure from Settings → AI & Agents. +* Add MCP servers, prompts, and global rules. +* Define Agent Profiles for read/write permissions, autonomy, and planning behavior. +* Maintain a global rules directory for consistent behavior across projects. + +Warp also supports codebase indexing, which creates embeddings for faster semantic search across your repos. + +--- + +### 7. Managing Agents Over Time + +Claude Code: + +* Shows progress directly in the CLI tab. +* Displays the current task name in the terminal tab title. + +Warp: + +* Adds visual indicators for agent status, progress, and toast notifications when blocked. +* Optional desktop notifications keep you informed when you’re multitasking. + +--- + +### 8. Performance Comparison + +Ben ran both tools on the same coding task — fixing a bug in the `renderKeyboardShortcut` function from a Sentry issue. + +Claude Code results: + +* Took \~2–4 minutes with Claude 3 Sonnet. +* Found the right issue and produced working code, though some redundant logic remained. + +Warp results: + +* With GPT-5, average time was \~1 minute 20 seconds. +* Consistent, high-quality output. +* Produced concise solutions with fewer redundant checks. +* Supported multiple models for experimentation. + +--- + +### 9. Conclusions + +| Criteria | Claude Code | Warp | +| --------------- | ----------------- | ------------------------ | +| Environment | CLI tool | Integrated into terminal | +| Diff Review | External / Manual | Built-in panel | +| Planning | Markdown mode | Inline or Opus-assisted | +| Model Options | Claude only | Claude, GPT-5, Gemini | +| Configurability | CLI-based | UI + Profiles + Rules | +| Performance | 2–4 min avg | \~1.2 min avg (GPT-5) | + +**TL;DR:**\ +If you prefer the Claude model suite and CLI workflow — go with Claude Code.\ +If you want richer diff editing, context referencing, and model flexibility — Warp is the better fit. + +> “Claude Code gives you an AI terminal. Warp gives you an AI development environment.” diff --git a/src/content/docs/guides/build-an-app-in-warp/building-a-chrome-extension-d3js-javascript-html-css.mdx b/src/content/docs/guides/build-an-app-in-warp/building-a-chrome-extension-d3js-javascript-html-css.mdx new file mode 100644 index 0000000..2ef4017 --- /dev/null +++ b/src/content/docs/guides/build-an-app-in-warp/building-a-chrome-extension-d3js-javascript-html-css.mdx @@ -0,0 +1,162 @@ +--- +title: Building a Chrome Extension (D3.js + Javascript + HTML + CSS) +description: >- + Build a D3.js Sankey diagram Chrome extension using Warp — scaffold, debug, + coordinate multiple agents, and publish to the Chrome Web Store. +sidebar: + label: "Build a Chrome extension" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +:::tip +This educational module teaches you step-by-step how to replicate the process shown in the video — building a **Sankey diagram Chrome extension** using **D3.js**, debugging, coordinating **multiple AI agents**, and deploying to the **Chrome Web Store**. +::: + +<VideoEmbed url="https://youtu.be/xbvE_aoZ508?si=a3-4iKaSr8nn-esx" /> + +<Steps> + +1. #### Set up your environment and create a new Chrome Extension project + + Our goal: build a Chrome extension called **“Sankey Stone”** that visualizes flows using **D3.js**. + + Files created during setup + + * `manifest.json` + * `popup.html` + * `popup.css` + * `popup.js` + * Icon images (`icon16.png`, `icon32.png`, `icon48.png`, etc.) + + Enable Developer Mode in Chrome and load the project: + + chrome://extensions → Developer Mode → Load unpacked → Select your project folder + + :::caution + If you see errors like “Failed to load extension” or “Could not load icon 16.png,” double‑check your manifest paths and icon filenames. The transcript explicitly shows these initial debugging steps. + ::: + +2. #### Test the initial D3.js rendering + + After fixing missing icons, the extension loads but initially shows only “Loading diagram.”\ + \ + Debug this by taking a screenshot and feeding it to an AI agent for context by asking: + + ``` + It says loading diagram — why isn’t the chart appearing? + ``` + + An agent reviews the error and regenerates the `popup.js` so the Sankey chart appears using **D3.js**. + + Result: a working, interactive diagram rendered inside the extension popup. + +3. #### Version control and GitHub setup + + Initialize a Git repository and commit: + + ```bash + git init + git add . + git commit -m "Initial Sankey Stone extension" + ``` + + The developer asks the agent to create a GitHub repo and push the code.\ + \ + The agent handles authentication, creates the remote repo, and pushes all files automatically. + +4. #### Add a local test page and dynamic data + + Launch a simple local web server with a test page that outputs traffic flow data. The extension reads this data and updates the Sankey diagram dynamically. + + Transcript example prompt: + + ``` + Update the test data page so that it generates random labels and different contexts when I hit the regenerate button. + ``` + + The agent edits the test page so that clicking the **Regenerate Test Page** button updates the diagram in real time. + +5. #### Coordinate multiple agents in parallel + + The video demonstrates running **multiple agents** in parallel. Each agent receives a different task: + + | Agent | Task | + | ----- | ----------------------------------------------------------------------------- | + | #1 | `Update the test data page to randomize labels and values` | + | #2 | `Change the refresh page button to regenerate the chart in a different style` | + | #3 | `Generate a useful README file for the project` | + + You can approve actions automatically by enabling **Auto‑approve all agent actions** so background updates run without manual confirmation. + + :::note + Running multiple agents in parallel mirrors having a small team: one agent focuses on data generation, another on UI changes, and a third on documentation. + ::: + +6. #### Refine styles and interactions + + After the data layer works, now you can iterate on appearance: + + ``` + Apply new color themes and improve the layout. + ``` + + Changes applied: + + * Support for multiple color themes and improved node layout. + * Hovering over links highlights connected nodes. + * Users can drag nodes to rearrange the layout. + * Added a “Switch Style” button to cycle between themes. + + To support exporting diagrams, you can ask: + + ``` + Add a button to download this image as a PNG. + ``` + + The Warp agent writes the JS logic for PNG export and verifies that clicking the button saves a screenshot of the diagram. + +7. #### Add an API key setup screen + + Create a settings page where users can store API keys: + + ``` + Add a settings page to enter the Anthropic API key and test it. + ``` + + * The page allows testing the key to ensure it works. + * API keys are stored locally in the browser, not sent to a server. + +8. #### Publish to the Chrome Web Store + + Package and submit the extension: + + ```bash + zip -r sankey_stone.zip * + ``` + + Upload the ZIP file to [https://chrome.google.com/webstore/devconsole](https://chrome.google.com/webstore/devconsole) and follow the prompts. + + :::note + The review may take a few weeks. + ::: + +</Steps> + +--- + +### Summary + +By following these transcript‑based steps, you can recreate the same workflow: + +* Scaffold a Chrome extension with D3.js. +* Debug manifest and icon issues. +* Use agents to generate and refine code. +* Introduce multi‑agent parallel tasks for UI, data, and docs. +* Add interactivity, themes, and export options. +* Create an API key setup screen. +* Package and publish to the Chrome Web Store. + +:::tip +You can follow this same pattern with your own idea: start small, scaffold with AI prompts, iterate using parallel agents, and deploy to production all from within Warp. +::: diff --git a/src/content/docs/guides/build-an-app-in-warp/building-a-real-time-chat-app-github-mcp-railway.mdx b/src/content/docs/guides/build-an-app-in-warp/building-a-real-time-chat-app-github-mcp-railway.mdx new file mode 100644 index 0000000..52526d2 --- /dev/null +++ b/src/content/docs/guides/build-an-app-in-warp/building-a-real-time-chat-app-github-mcp-railway.mdx @@ -0,0 +1,234 @@ +--- +title: Building a Real-time Chat App (Github MCP + Railway ) +description: >- + Build and deploy a real-time chat app with Python, FastAPI, and JavaScript — + from idea to production, all inside Warp. +sidebar: + label: "Build a real-time chat app" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +:::note +In this tutorial, we’ll follow along with Tech With Tim’s _Advanced Vibe Coding Tutorial w/ Warp_ video.\ +\ +You’ll learn how to use **Warp**, the _agentic development environment_, to build and deploy a fullstack AI-driven app from scratch — including setup, debugging, and deployment using **GitHub MCP servers**. +::: + +<VideoEmbed url="https://www.youtube.com/watch?v=Pxp9mB51U-A" title="Advanced Vibe Coding Tutorial w/ Warp (Build & Deploy Apps)" /> + +### Overview + +This video shows how to go from **idea → working web app → production deployment**, all inside Warp.\ +The project: a **real-time chat application** built with **Python (FastAPI)** and a **JavaScript frontend**, deployed through **Railway**, and integrated with **GitHub** via **MCP (Model Context Protocol)**. + +<Steps> + +1. #### Setup & Installation + + :::note + Warp is free for Mac, Linux, and Windows. Download it from [https://warp.dev](https://warp.dev/) and sign in with an account. + ::: + + Once you open Warp, you’ll see three core modes: + + * **Auto Mode** – Detects whether you’re typing a command or an AI prompt + * **Terminal Mode** – For standard shell commands only (`ls`, `pwd`, etc.) + * **Agent Mode** – For conversational AI prompts (`build me an app`, `add feature X`, etc.) + + You can switch modes using the top-bar buttons. + + Pro tip: Enable voice input for natural prompting or attach screenshots when debugging UI issues. + +2. #### Generate an App Idea + + Warp supports _planning models_, where the AI generates a detailed roadmap before coding. + + ``` + I would like to make something of simple to medium complexity that I could finish in about 30 minutes. I want this to be web based. I want to have some kind of interface and some kind of backend. Can you give me a fun idea that's not going to be too complicated to build out and to eventually deploy? + ``` + + The AI suggested several projects, like a personal mood tracker, quick poll creator, recipe randomizer, and more.\ + \ + Chosen idea we went with: **a real-time chat application**. + +3. #### Create a Development Plan + + Prompt: + + ```bash + I like idea one. Can you come up with a detailed plan on how to build this? + ``` + + Warp’s agent generated a plan for: + + * A **frontend** (UI for chat rooms and messages) + * A **backend** (FastAPI server for real-time communication) + * Database integration and planned deployment steps + + You can refine or expand the plan interactively by prompting: + + ``` + Make this more detailed. + ``` + + And get back something like this: + + ``` + + Here's your development roadmap: + + 🏗️ Architecture Decisions + Frontend Options: + • React + Socket.IO Client (recommended for rich UI) + • Vue.js + Socket.IO Client + • Vanilla JS + WebSockets (simpler but limited) + + Backend Options: + • Node.js + Socket.IO + Express (most popular for real-time) + • Python + Flask-SocketIO + • Go + Gorilla WebSocket + + Database: + • MongoDB (flexible for chat messages) + • PostgreSQL (structured data with JSON fields) + • Redis (for session management and caching) + + 🚀 Recommended Tech Stack + 📋 Core Features to Implement + 1. Real-time messaging (Socket.IO) + 2. User authentication (JWT) + 3. Multiple chat rooms + 4. Online user presence + 5. Message history + 6. Typing indicators + 7. File/image sharing (optional) + + 🛠️ Development Steps + 1. Create project in ~/Documents/Coding_Projects/realtime-chat + 2. Set up Node.js backend with Socket.IO + 3. Create React frontend with real-time connection + 4. Implement user auth and room management + 5. Add message persistence and history + 6. Style UI and add advanced features + ``` + + At any point, you can go into the plan and start directly modifying it. And when you're ready, you can tell Warp to: + + ```bash + Please execute this plan. + ``` + +4. #### Allow Autonomous Execution + + Once Warp starts executing, you can let Warp run commands automatically: + + 1. Go to **Settings → AI → Agents** + 2. Change **“Always Ask”** → **“Always Allow”** + 3. Ensure restricted commands (e.g., `rm -rf`) remain blocked + + This enables autonomous execution for safe, fast iteration. Warp will run shell commands, create directories, initialize files, and write code. + +5. #### Running the App + + First, you can click into any file, like `main.py` to edit it directly in Warp. Warp displays your file directly in the app for easy editing, similar to any regular IDE experience. + + ![Editing main.py directly in Warp's built-in code editor](../../../../assets/guides/Screenshot-2025-10-07-at-10.44.14-AM.png) + + You can also ask Warp to run the app and test locally: + + ``` + Can you run this app for me so I can test it? Tell me how to view it. + ``` + + It's possible (like in the video) for an error to occur (e.g., Internal Server Error). If that happens, y you can simply debug conversationally: + + ```bash + I’m getting an internal server error. Can you fix this? + ``` + + And Warp can fix the issue and rerun the app automatically. + +6. #### Adding New Features + + To enhance the app, request features conversationally: + + ``` + Can you add emoji reactions to the messages? + ``` + + Warp will modify frontend and backend code, updating WebSocket logic for real-time reactions. After testing, multiple users can now react to messages in the chat interface. + +7. #### Preparing for Deployment + + Warp integrates directly with version control and cloud deployers via **MCP servers**. + + Connect GitHub MCP: + + 1. Go to **Settings → AI → MCP Servers → Add** + 2. Add a JSON block for GitHub MCP: + + ```json + { + "github": { + "command": "docker", + "args": [ + "run", + "-i", + "--rm", + "-e", + "GITHUB_PERSONAL_ACCESS_TOKEN", + "ghcr.io/github/github-mcp-server" + ], + "env": { + "GITHUB_PERSONAL_ACCESS_TOKEN": "${<INSERT_YOURS_HERE>}" + } + } + } + ``` + + 3. Generate a GitHub personal access token (Settings → Developer Settings → Tokens) + * Enable scopes for: `repo`, `workflow`, `secrets`, `pull_request`, and `environments`. + + Save and restart Warp. + + Then tell the agent: + + ``` + Can you make a new remote repo for me and upload my code? + ``` + + Warp uses Git commands automatically: + + ```bash + git init + git add . + git commit -m "Initial commit" + git remote add origin ... + git push + ``` + +8. #### Deploying via Railway + + Prompt: + + ``` + I have a FastAPI application built with Python. I want to deploy this. It just has an integrated frontend with JavaScript, HTML, and CSS. What’s the easiest way to do that? Can you assist me? + ``` + + Warp recommends **Railway** and walks through: + + * Creating a Railway account + * Connecting your GitHub repo + * Deploying directly from GitHub + * Generating a public domain + + Once deployed, test it in your browser — you’ll see your live chat app with emoji reactions working in real time. + +</Steps> + +### Appendix + +* [Github MCP Server](https://github.com/github/github-mcp-server) +* [Docker Desktop download](https://www.docker.com/products/docker-desktop/) +* [Railway](https://railway.com/) diff --git a/src/content/docs/guides/build-an-app-in-warp/building-a-slackbot.mdx b/src/content/docs/guides/build-an-app-in-warp/building-a-slackbot.mdx new file mode 100644 index 0000000..ce6f06b --- /dev/null +++ b/src/content/docs/guides/build-an-app-in-warp/building-a-slackbot.mdx @@ -0,0 +1,122 @@ +--- +title: Building a Slackbot +description: >- + Set up a self-hosted Warp Slackbot that answers repo questions and opens PRs + directly from Slack using Docker and GitHub integration. +sidebar: + label: "Build a Slackbot" +--- +import { Steps } from '@astrojs/starlight/components'; + +This guide shows you how to spin up a [Warp Slackbo**t**](https://github.com/warpdotdev/warp-slackbot-public) you can mention in Slack to answer questions about your repositories and even open pull requests. It runs securely in Docker and connects directly to your Slack workspace. + +The setup takes just a few steps — clone, configure, and run — and requires minimal setup beyond providing your own Slack, GitHub, and Warp credentials. + +## Why this is useful + +* Run a self-hosted Slack bot that connects your team’s repos and Warp AI agents. +* Provide your team with a coding assistant that can answer repo questions or help with PRs directly in Slack. + +## Quickstart Setup + +<Steps> + +1. #### Clone the repository + + Clone the public repo and navigate into it: + + ```bash + git clone https://github.com/warpdotdev/warp-slackbot-public.git + cd warp-slackbot-public + ``` + + This repository includes all required configuration templates, the Docker setup, and the app manifest you’ll use to create your Slack bot. + +2. #### Configure environment variables + + Copy the provided example environment file and fill in your credentials: + + ```bash + cp .env.example .env + ``` + + Then open `.env` and fill in the following values: + + * `SLACK_BOT_TOKEN` – Your bot token from Slack, which starts with `xoxb-`. You can find this under your Slack app’s **OAuth & Permissions** page. + * `SLACK_APP_TOKEN` – Your app-level token from Slack, which starts with `xapp-`. Create this in your Slack app’s **Basic Information → App-Level Tokens**, and ensure it has the `connections:write` scope (required for Socket Mode). + * `GITHUB_PAT` – Your GitHub Personal Access Token (PAT) with `repo` access, so the bot can read and clone your repositories. + * `WARP_API_KEY` – Your Warp API key that allows the bot to connect to Warp’s agentic environment and execute prompts. + + You only need to create these once — after saving your `.env` file, Docker will automatically read them when you run the bot. + +3. #### Configure repositories + + Copy the provided repository configuration template: + + ```bash + cp repos.yaml.template repos.yaml + ``` + + Then open `repos.yaml` and list the repositories you want the bot to monitor, for example: + + ```yaml + repositories: + - url: "myorg/backend" + branch: "main" + - url: "myorg/frontend" + branch: "develop" + ``` + + This file tells the bot which repositories to clone locally and keep up to date. It’s how the bot knows where to pull context from when you ask it repo-related questions. + + What’s happening behind the scenes: + + * The bot will use your GitHub PAT to clone each listed repo. + * It stores the repositories in a persistent Docker volume so you don’t have to re-clone each time. + * The bot indexes those repos for context so it can respond intelligently when mentioned in Slack. + +4. #### Understand the Slack App Manifest + + The file `slack_app_manifest.json` defines everything needed to create your Slack app quickly — including permissions, event subscriptions, and bot scopes. When creating your Slack app, you can paste the contents of this file directly into the **Slack App → Create from Manifest** interface. It configures the bot to: + + * Listen for mentions and thread replies (`app_mention` events) + * Run via Socket Mode (secure WebSocket connection) + * Send and receive messages in channels where it’s invited + +5. #### Run the bot in Docker + + Once your `.env` and `repos.yaml` files are ready, start the bot: + + ```bash + docker-compose up --build + ``` + + This builds the container, authenticates with Slack and GitHub, and starts listening for messages. It will log all activity in your terminal so you can confirm it’s running. + +6. #### Test in Slack + + * Invite your bot to a channel in Slack. + * Mention it directly or in a thread to trigger it — for example: + + ``` + @Warp analyze the recent changes in the main branch + @Warp help me review this PR + ``` + + * The bot will pull context from your configured repositories and reply with AI-assisted insights using Warp’s agentic platform. + +</Steps> + +## What happens on startup + +* Reads `.env` and `repos.yaml`. +* Authenticates to Slack (Socket Mode and Web API). +* Authenticates to GitHub and clones the listed repos. +* Starts listening for `app_mention` events and threaded messages. +* Routes context and commands to Warp’s AI agent backend. + +You can stop the bot anytime with `Ctrl + C` or run it persistently with: + +```bash +docker-compose up -d +``` diff --git a/src/content/docs/guides/build-an-app-in-warp/building-warps-input-with-warp.mdx b/src/content/docs/guides/build-an-app-in-warp/building-warps-input-with-warp.mdx new file mode 100644 index 0000000..54a369b --- /dev/null +++ b/src/content/docs/guides/build-an-app-in-warp/building-warps-input-with-warp.mdx @@ -0,0 +1,59 @@ +--- +title: Building Warp's Input - With Warp +description: >- + Watch how a Warp designer uses Warp's own agent to locate, modify, and test + a UI component change in a large Rust codebase. +sidebar: + label: "Build Warp's input component" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +_Speaker: Dave, Product Design Lead at Warp_ + +<VideoEmbed url="https://youtu.be/ySzUj7kMZ64?si=MBhB4s_6lMDWHeS6" /> + +### The Challenge + +Redesigning the input was tricky because it’s the primary interface developers use all day, every day.\ +Everyone had opinions — and expectations — about how it should look and behave. + +So, Peter (a product designer on my team) and I iterated on multiple designs using Figma. + +Once we landed on a version we liked, we shared it internally.\ +Most people were excited, but engineering resources were stretched thin — focused on improving agent-mode quality and prepping the Agentic Development Environment. + +So I thought: _“What if I just Warp it?”_ + +#### Step 1. Locating the Git Diff Chip Code + +Inside the universal input, there’s a small Git Diff chip — it shows your current branch and open changes. It was one pixel too tall. That tiny visual bug drove me nuts, so I used Warp to find where it lived. + +Warp searched across the entire codebase and found references inside: + +* `displaychip.rs` +* Related render and configuration files + +It used a combination of semantic search, code indexing, and traditional grep to pinpoint the exact implementation. + +--- + +#### Step 2. Modifying the Font Size + +Once Warp located the implementation, I asked it to reduce the font size by 1 pixel. + +Warp automatically edited the relevant lines: + +* Found the current setting (`system_font_size - 1`) +* Adjusted it to (`system_font_size - 2`) + +I reviewed the diffs to confirm everything looked good. + +--- + +#### Step 3. Building and Testing the Change + +Next, I rebuilt the app using: + +```bash +cargo run +``` diff --git a/src/content/docs/guides/configuration/creating-rules-for-agents.mdx b/src/content/docs/guides/configuration/creating-rules-for-agents.mdx new file mode 100644 index 0000000..5a46b6b --- /dev/null +++ b/src/content/docs/guides/configuration/creating-rules-for-agents.mdx @@ -0,0 +1,50 @@ +--- +title: Creating Rules For Agents +description: >- + Create reusable Rules in Warp to encode team conventions — like Dockerfile + patterns or dependency management — so agents follow your standards. +sidebar: + label: "Create Rules for Agents" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +_Speaker: Maggie — Engineer at Warp_ + +<VideoEmbed url="https://youtu.be/OyrpkeL6WNY?si=E1rDShRA0CisOwZp" /> + +### 1. Starting with Agent Mode Evals + +I’m currently adding **Evals** (short for evaluations) to test a new feature I’ve been building. + +Warp quickly surfaces helpful context — like notebooks and internal docs — written by teammates on how to run Evals.\ +\ +This makes onboarding onto new tasks fast and collaborative. + +--- + +### 2. Adding a Rust Syntax Eval + +Next, I want to add an Eval that tests for Rust syntax errors.\ +So I ask Warp to update the Dockerfile to include Rust. + +However, the generated Dockerfile installs Rust differently than I wanted.\ +It also includes `gcc` and `python` via a single `apt-get` line, which doesn’t follow our internal conventions. + +--- + +### 3. Stashing Changes & Creating a Rule + +Instead of fixing this manually every time, I decide to stash the current changes and create a reusable Rule that encodes our convention: + +> Rule Example:\ +> “Always use `apt-get` to install packages and follow the same pattern used for installing Python and GCC.” + +This way, future sessions — and even other teammates — can automatically apply the same standard. + +--- + +### 4. Applying the Rule + +Now, I just ask Warp’s Agent Mode to try again! + +Warp re-runs the request, follows the new rule, and correctly adds Rust with the right syntax. The code now matches our conventions. diff --git a/src/content/docs/guides/configuration/how-to-configure-yolo-and-strategic-agent-profiles.mdx b/src/content/docs/guides/configuration/how-to-configure-yolo-and-strategic-agent-profiles.mdx new file mode 100644 index 0000000..b8f0273 --- /dev/null +++ b/src/content/docs/guides/configuration/how-to-configure-yolo-and-strategic-agent-profiles.mdx @@ -0,0 +1,108 @@ +--- +title: "How To: Configure YOLO and Strategic Agent Profiles" +description: >- + Configure custom agent profiles in Warp to control planning depth, autonomy, + and execution speed — demonstrated with YOLO and Strategic examples. +sidebar: + label: "Configure YOLO and Strategic Agent Profiles" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +:::note +This tutorial explains how **Agent Profiles** in Warp influence behavior, autonomy, and planning when coding with AI — demonstrated through the NFL Predictor app example. +::: + +<VideoEmbed url="https://youtu.be/iD0R-8fY-tY?si=FCX9yVq5_BRUognp" /> + +<Steps> + +1. #### Define the Project + + I want to create an app that scrapes **NFL data** from the past decade, processes stats like team scores and player performance, and predicts future wins. + + The prompt specifies: + + * Data sources and constraints + * Dependencies and CLI commands + * Implementation details and deliverables + + ``` + Role & Goal + You are my AI coding copilot inside Warp. + Create a production-ready Python project that ingests 2015–2025 NFL data to power future win projections. + + Specifically: acquire week-level player and team stats, acquire game schedules + final scores (to determine weekly winners), and assemble a clean analytics dataset I can build models on later. Prefer stable/public data sources over brittle HTML scraping. Where scraping is unavoidable, respect robots.txt, add rate-limiting, and make scraping pluggable/optional. + + Primary data sources: + nflverse/nflreadr static files for weekly player stats and schedules (CSV/Parquet over HTTPS). + + Tech constraints: + Python 3.11+, no notebooks in the main flow. + Deterministic, idempotent pipelines. + Strong typing (pydantic) + docstrings. + Parquet as the storage format; small sample CSVs for quick checks. + CLI via Typer (warp run … friendly). + Logging (structlog), retry/backoff (tenacity), polite rate-limits. + Zero secrets required for core pipeline. + + Deliverables: + A fully initialized repo with the scaffold above. + Implemented CLI + modules to download/ingest 2015–2025 data, compute/normalize fantasy PPR, produce winners by week, and write Parquet outputs. + One sample run in the README showing commands and example output counts. + If successful, run full 2015–2025. + Print a summary table (by season: games, players, weeks) at the end. + ``` + +2. #### Configure the Strategic Agent + + **Base Model:** GPT‑5 (for reasoning)\ + **Planning Model:** Claude 4 Opus (for detailed breakdowns) + + | Action | Permission | + | ---------------- | ------------- | + | Apply code diffs | Agent decides | + | Read files | Agent decides | + | Create plans | Always allow | + | Execute commands | Always ask | + + Behavior: + + * The agent starts by asking clarifying questions: + + > “Do you want me to scrape both player stats and schedules or just one first?”\ + > “Where should raw data be stored — locally or in a database?” + * It builds a **14-step plan** covering setup, dependencies, validation modules, and pipelines. + * When the agent requests NFL schedule URLs, the chosen source returns 404 errors. + * Execution halts — showing that the **Strategic** profile prioritizes verification over progress. + +3. #### Configure the YOLO Agent + + **Permissions:** + + | Action | Permission | + | ------------------------ | ------------ | + | Apply diffs / read files | Always allow | + | Create plans | Never | + | Execute commands | Always allow | + + Behavior: + + * The YOLO agent skips detailed planning. + * It produces a **10-step plan** that covers essentials only: + * Initialize project + * Build CLI + * Ingest player data + * Compute scores and transformations + * Instead of using unstable schedule URLs, it focuses on reliable player endpoints — completing a functional data pipeline. + +4. #### Compare Outcomes + +</Steps> + +| Aspect | Strategic Agent | YOLO Agent | +| ----------- | ----------------------- | -------------------------------------- | +| Planning | Detailed (14 steps) | Minimal (10 steps) | +| Interaction | Clarifications required | Autonomous | +| Speed | Slower due to checks | Faster iteration | +| Output | Stalled on invalid URLs | Working player dataset + summary table | diff --git a/src/content/docs/guides/configuration/how-to-create-project-rules-for-an-existing-project-astro-typescript-tailwind.mdx b/src/content/docs/guides/configuration/how-to-create-project-rules-for-an-existing-project-astro-typescript-tailwind.mdx new file mode 100644 index 0000000..c0a4e61 --- /dev/null +++ b/src/content/docs/guides/configuration/how-to-create-project-rules-for-an-existing-project-astro-typescript-tailwind.mdx @@ -0,0 +1,229 @@ +--- +title: "How To: Create Project Rules for an Existing Project (Astro + Typescript + Tailwind)" +description: >- + Create and maintain an AGENTS.md project rules file so coding agents always + understand your project's setup, commands, architecture, and conventions. +sidebar: + label: "Create Project Rules for an existing project" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps, FileTree } from '@astrojs/starlight/components'; + +:::note +This educational module is built **only** from the transcript. It shows how to create and maintain a `Warp.md` file so Warp agents always understand your project’s setup, commands, architecture, and structure. +::: + +<VideoEmbed url="https://youtu.be/SCYovBn4TnM?si=7wZEuTQAFUpcoFJx" /> + +--- + +## What Project Rules Are + +A **Project Rules** file (`Warp.md`) acts as your project’s AI onboarding guide. Instead of re‑explaining your setup on every prompt, you document it once and Warp will always have that context. The transcript demo walks through creating the file, opening it in a side editor, and organizing it with standard Markdown headings for clear sections. + +--- + +## Generate `Warp.md` + +Run the following **verbatim** prompts in Warp to create and verify your rules file, then open it in the editor: + +``` +/init +``` + +``` +/open-project-rules +``` + +* `/init` generates a starter `Warp.md` in your project root. +* `/open project rules` opens it in a side editor where you can scroll and edit the content. + +You'll get something that looks like this: + +````markdown +# WARP.md + +This file provides guidance to WARP (warp.dev) when working with code in this repository. + +## Project Overview + +Share Your Brewfiles is an Astro-based website that allows developers to share and discover their Homebrew package lists (Brewfiles). The platform generates personality profiles based on package usage patterns and provides a leaderboard of popular packages. + +## Core Architecture + +* **Frontend**: Astro 4 with React 18 components, TypeScript, and Tailwind CSS +* **Backend**: Astro API routes with Firebase integration +* **Database**: Firebase Firestore for storing brewfiles, user data, and personality summaries +* **Deployment**: Vercel with serverless functions +* **Styling**: Custom Tailwind configuration with dark theme and gradient animations + +## Key Components + +### API Routes (`src/pages/api/`) +* `getBrewfiles.json.ts` - Retrieves all brewfiles or a specific brewfile by ID, triggers personality generation +* `uploadBrewfile.ts` - Handles brewfile uploads with GitHub OAuth integration +* `getRankedPackages.json.ts` - Generates leaderboard data for popular packages +* `updatePersonality.ts` - Updates personality summaries for users +* `exchangeCodeForAccessToken.ts` - GitHub OAuth token exchange +* `logSearch.json.ts` - Analytics for search functionality + +### Core Library Functions (`src/lib/`) +* `generatePersonality.ts` - Complex algorithm that analyzes brewfile packages and assigns personality types (15 different personalities) +* `personalityBuckets.ts` - Defines personality type metadata and descriptions +* `validateBrewfileData.ts` - Data validation for brewfile uploads +* `totalBrewData.ts` - Aggregates package statistics for leaderboards + +### Type System (`src/types/`) +* `brews.ts` - Main data structures for brewfiles, users, and entries +* `personality.ts` - Personality analysis types and enums +* `packageEntry.ts` - Package metadata structures + +## Development Commands + +### Setup +```bash +# Install dependencies +npm install + +# Set up environment (Firebase config is public but consider security) +# No additional env setup needed for development + +# Development server +npm run dev +``` + +### Development Workflow +```bash +# Start development server with Astro +npm run dev + +# Build for production +npm run build + +# Preview production build +npm run preview + +# Run Astro CLI commands +npm run astro +``` + +### Testing API Endpoints +```bash +# Test brewfile retrieval +curl "http://localhost:4321/api/getBrewfiles.json" + +# Test specific brewfile by ID +curl "http://localhost:4321/api/getBrewfiles.json?id=DOCUMENT_ID" + +# Test package rankings +curl "http://localhost:4321/api/getRankedPackages.json" +``` + +## Architecture Notes + +### Personality Generation System +The core feature analyzes brewfile packages against a curated dictionary (`labelledBrewfiles.ts`) that categorizes packages by: +- Developer type (Backend, Frontend, DevOps, Security, Data, General) +- Package characteristics (AI tools, organization tools, customization, popularity rank) +- Legacy/modern status + +The system calculates percentage distributions and applies complex rules to assign one of 15 personality types (Minimalist, Golden Retriever, Pragmatist, Trendy, AI, Architect, Artist, Traditionalist, Retro, Bob the Builder, Marie Kondo, Crazy Scientist, Trailblazer, Security, Wallflower). + +### Firebase Integration +- Uses Firestore for data persistence +- Collection: `brewfiles` stores user brewfiles with personality summaries +- Real-time personality generation happens asynchronously after uploads +- GitHub OAuth integration for user authentication + +### Path Alias System +Uses TypeScript path mapping with `@/*` pointing to `./src/*` for clean imports. + +### Astro Configuration +- Server-side rendering with Vercel adapter +- React integration for interactive components +- Sitemap generation for SEO +- Prefetch enabled for performance + +## Development Environment Setup + +### Prerequisites +- Node.js (version compatible with Astro 4) +- Access to Firebase project (config is in source but consider security implications) +- GitHub OAuth app for testing upload functionality + +### Local Development Notes +- The site uses server-side rendering so API routes work in development +- Firebase config is currently in source code - be aware of security implications +- GitHub OAuth integration requires valid access tokens for uploads +- Personality generation is computationally expensive with large datasets + +### Custom Tailwind Configuration +- Dark theme with custom color palette (`bkg: #111111`) +- Custom accent colors (teal, orange, green, pink, blue variants) +- Marquee animations for scrolling elements +- Responsive typography with fluid scaling +- Container queries support + +## File Structure Navigation +<FileTree> +- src/ + - pages/ + - api/ Astro API routes (serverless functions) + - index.astro Homepage with hero and marquee + - brewfiles.astro Search and browse brewfiles + - leaderboard.astro Package popularity rankings + - components/ Astro and React components + - lib/ Core business logic and utilities + - types/ TypeScript type definitions + - data/ Static data and package dictionaries + - firebase/ Firebase configuration +</FileTree> + +## Common Development Tasks + +### Adding New Personality Types +1. Update `DeveloperPersonalityType` enum in `src/types/personality.ts` +2. Add detection function in `src/lib/generatePersonality.ts` +3. Update `personalityBuckets.ts` with new personality metadata +4. Add corresponding image to `public/images/` + +### Modifying Package Analysis +- Update `labelledBrewfiles.ts` to modify package categorization +- Adjust percentage thresholds in personality detection functions +- Test with different brewfile compositions + +### API Route Development +- All routes in `src/pages/api/` become serverless functions on Vercel +- Use `export const prerender = false;` for dynamic routes +- Handle errors consistently with try/catch blocks +```` + +--- + +## Keep the File Lean and Intentional + +<Steps> + +1. #### Start Lean + + Everything in `warp.md` is **prepended to your prompt**. A longer file consumes more tokens and can increase compute cost. Keep only what truly matters. + +2. #### Iterate and Maintain + + Start with `/init` boilerplate, then treat the file as a **living document**. Add the rules that help your team ship faster (e.g., branching, PR guidelines) and prune anything redundant. + +</Steps> + +:::caution +If the file grows large (e.g., **500+ lines**), run it through a **prompt optimizer** to catch duplication, remove overlaps, and slim it down — exactly as advised in the transcript. +::: + +--- + +## Use Sub‑directory Rules for Monorepos + +For large repos, you can generate localized rule files in sub‑trees. Navigate into a subfolder and run `/init` again to create a **directory‑scoped `Warp.md`** tailored to that area: + +:::tip +Going forward, when you give Warp a task, it will carry this context automatically — no re‑explaining needed. +::: diff --git a/src/content/docs/guides/configuration/how-to-set-coding-best-practices.mdx b/src/content/docs/guides/configuration/how-to-set-coding-best-practices.mdx new file mode 100644 index 0000000..c95ed7a --- /dev/null +++ b/src/content/docs/guides/configuration/how-to-set-coding-best-practices.mdx @@ -0,0 +1,56 @@ +--- +title: "How To: Set Coding Best Practices" +description: >- + Use Warp Rules to enforce coding style, TypeScript conventions, and + documentation quality across AI-generated code. +sidebar: + label: "Set coding best practices" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +Learn how to use Warp’s Rules to enforce coding style, documentation quality, and consistency across projects. + +<VideoEmbed url="https://youtu.be/AuM2OIvXlnY?si=rxnQH5TH-5vj0LMf" /> + +--- + +## Intro + +This tutorial teaches you how to create coding Rules that make AI follow your team’s **best practices** automatically.\ +\ +By specifying formatting, style preferences, and documentation standards, Warp ensures consistent, high-quality code across your repositories. + +--- + +<Steps> + +1. #### The Problem + + Developers often have different habits — formatting styles, TypeScript conventions, or comment quality.\ + Without clear rules, AI-generated code can be inconsistent or hard to maintain. + +2. #### The Rule Setup + + Define Rules that enforce formatting, type preferences, and doc quality. + + **Example Rule** + + ``` + Rule: Code Authoring Standards + - Always format and check work before returning results. + - Prefer `types` over `interfaces` in TypeScript. + - Apply concise, human-readable JS Docs using the Hemingway test. + ``` + + :::note + The **Hemingway test** ensures code comments are simple and clear — short sentences, active voice, and no unnecessary complexity. + ::: + +3. #### Benefits + + * Encourages readable, maintainable code + * Improves documentation clarity + * Prevents style drift across AI contributions + +</Steps> diff --git a/src/content/docs/guides/configuration/how-to-set-coding-preferences-with-rules.mdx b/src/content/docs/guides/configuration/how-to-set-coding-preferences-with-rules.mdx new file mode 100644 index 0000000..a8e7939 --- /dev/null +++ b/src/content/docs/guides/configuration/how-to-set-coding-preferences-with-rules.mdx @@ -0,0 +1,50 @@ +--- +title: "How To: Set Coding Preferences with Rules" +description: >- + Store your package manager, environment tool, and CLI preferences as Warp + Rules so agents automatically use pnpm, miniconda, or your preferred tools. +sidebar: + label: "Set coding preferences with Rules" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +Learn how to use Warp’s Rules feature to define your personal environment and tool preferences for every coding session. + +<VideoEmbed url="https://youtu.be/zWvRB2zWr-4?si=tv-TIhsqEtLG9iDs" /> + +This tutorial teaches you how to customize your development setup using **Warp’s Rules** — ensuring the AI agent always works in your preferred environment. Instead of constantly reminding it which package manager or environment to use, you can **store those preferences as persistent Rules** that apply automatically across projects. + +<Steps> + +1. #### The Problem + + When using AI tools to write or modify code, they often default to outdated or undesired tools.\ + For example, many agents still use **npm** instead of **pnpm** — or **pip** instead of **miniconda**. + + Warp fixes this by letting you define your preferences once, and then applying them automatically whenever your agent runs commands. + +2. #### The Rule Setup + + You can set Rules for how you want the AI to handle environments, dependencies, and commands. + + **Example Rule** + + ``` + Rule: Environment Preferences + - Always use pnpm for Node.js projects unless the project already uses npm. + - Default to miniconda for Python environments. + - Use the Tauri CLI when building desktop apps. + ``` + This ensures the agent automatically chooses the right package manager or environment — no extra prompts required. + +3. #### Supported Use Cases + + You can apply Rules to: + + * Package managers (e.g., npm → pnpm) + * Environment tools (e.g., virtualenv → miniconda) + * Framework defaults (e.g., Next.js over React) + * CLI utilities or custom build tools + +</Steps> diff --git a/src/content/docs/guides/configuration/how-to-set-tech-stack-preferences-with-rules.mdx b/src/content/docs/guides/configuration/how-to-set-tech-stack-preferences-with-rules.mdx new file mode 100644 index 0000000..ec6c63f --- /dev/null +++ b/src/content/docs/guides/configuration/how-to-set-tech-stack-preferences-with-rules.mdx @@ -0,0 +1,64 @@ +--- +title: "How To: Set Tech Stack Preferences with Rules" +description: >- + Define your preferred frameworks and tech stack in Warp Rules so agents + consistently use Astro, SvelteKit, Vite, or your tools of choice. +sidebar: + label: "Set tech stack preferences with Rules" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Learn how to guide Warp’s AI to use your favorite tech stack when scaffolding new apps or generating code. + +<VideoEmbed url="https://youtu.be/W5B6MhZsZ_4?si=Bd9AT0cnW6uiMhKO" /> + +--- + +## Intro + +This tutorial walks you through teaching Warp’s AI your **preferred technologies** so it consistently uses the frameworks and stacks you care about. + +By setting up tech stack Rules, you make sure every new project follows your conventions — whether you prefer **Astro**, **SvelteKit**, **Next.js**, or something else. + +--- + +## The Problem + +When you ask AI to scaffold a new web app, it often defaults to **React** and **Express**, or other older stacks.\ +This creates friction when your workflow is based on modern tools or opinionated frameworks. + +Warp solves this by letting you **store your stack preferences** directly as Rules. + +--- + +## The Rule Setup + +Create a simple Rule that defines your favorite frameworks for each project type. + +### Example Rule + +``` +Rule: Tech Stack Preferences +- Use Astro for websites. +- Use SvelteKit for desktop apps. +- Prefer Vite for build tooling. +- Avoid legacy stacks like Create React App or Express. +``` + +Once added, Warp’s AI automatically applies these defaults when generating new projects or updating existing ones. + +:::note +Think of it like setting a default coding personality for your agent. +::: + +--- + +## Why It Matters + +:::tip +Defining your stack preferences helps the AI: + +* Generate **consistent boilerplates** +* Follow your **current tech standards** +* Skip outdated or irrelevant dependencies +::: diff --git a/src/content/docs/guides/configuration/how-to-set-up-self-serve-data-analytics-with-skills.mdx b/src/content/docs/guides/configuration/how-to-set-up-self-serve-data-analytics-with-skills.mdx new file mode 100644 index 0000000..65eb99a --- /dev/null +++ b/src/content/docs/guides/configuration/how-to-set-up-self-serve-data-analytics-with-skills.mdx @@ -0,0 +1,186 @@ +--- +title: "How to set up self-serve data analytics with Skills" +description: >- + Set up a self-serve data analytics workflow in Warp using two community + Skills that map questions to dbt models and structure reproducible analyses. +sidebar: + label: "Set up self-serve data analytics with Skills" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Self-serve data analytics means anyone on your team can ask a data question and get a trustworthy answer, without pinging the data team. This guide sets up that workflow using two community Skills that chain together: one resolves vague questions to the right BigQuery tables, and the other structures deep-dive analyses into reproducible folders. Plan on about 10 minutes for initial setup, plus time to customize the model index for your warehouse. + +## Prerequisites + +* **Warp** — Install from [warp.dev](https://www.warp.dev/download) if you don't already have it. +* **A BigQuery data warehouse with dbt models** — The Skills as published assume BigQuery and dbt. You can adapt them to Snowflake, Redshift, Databricks, or a non-dbt setup. See [Adapting to your stack](#adapting-to-your-stack). +* **The BigQuery CLI (`bq`)** — Installed as part of the [Google Cloud SDK](https://cloud.google.com/sdk/docs/install). Agents call it directly to query the warehouse, so no MCP server is required. +* **A Git repository where the Agent will work** — Warp auto-discovers Skills from `.agents/skills/` in your current working directory up through the repo root. See [Skills](https://docs.warp.dev/agent-platform/capabilities/skills/) for the full list of supported directories and how discovery works. + +## Walkthrough video + +In this 40-minute livestream, Warp's data team demonstrates the workflow end-to-end, including the two Skills you'll install below and a third pattern (running the same Skills from Slack via an Oz cloud agent). Feel free to skip ahead if you prefer to follow the written steps. + +<VideoEmbed url="https://www.youtube.com/watch?v=WyMTjXSplRU" /> + +## 1. Install the two Skills + +Warp automatically discovers any Skill stored under `.agents/skills/` in your repo, so committing the two directories makes them available to every teammate's Agent runs. Clone the public [warpdotdev/oz-skills](https://github.com/warpdotdev/oz-skills) repo and copy the two Skill directories into your own dbt repo: + +```bash +cd /path/to/your/dbt-repo +mkdir -p .agents/skills +git clone https://github.com/warpdotdev/oz-skills.git /tmp/oz-skills +cp -r /tmp/oz-skills/.agents/skills/dbt-model-index .agents/skills/ +cp -r /tmp/oz-skills/.agents/skills/analysis-artifacts .agents/skills/ +``` + +Verify both Skills landed: + +```bash +ls .agents/skills/ +# analysis-artifacts dbt-model-index +``` + +Commit the Skills. Once committed to your repo, they are available to the whole team: + +```bash +git add .agents/skills && git commit -m "Add self-serve analytics skills" +``` + +## 2. Customize the dbt model index + +The [`dbt-model-index`](https://github.com/warpdotdev/oz-skills/blob/main/.agents/skills/dbt-model-index/SKILL.md) Skill is a template that you will need to fill in with details about your own models. This Skill teaches the Agent which tables answer which question types, so it's important to spend time on customization. Detailed "Useful for" descriptions make the Skill most effective. + +Open `.agents/skills/dbt-model-index/SKILL.md` and replace the template placeholders with real models. For each one, include: + +* The table name (backtick-formatted) +* A 1- to 2-sentence description of its grain +* "Useful for:" bullets covering the question types it answers + +A filled-in entry might look like this: + +```markdown +### `users_daily` + +One row per user per day, with activity signals and plan type. + +**Useful for:** + +- Daily, weekly, or monthly active user counts +- Retention and churn by plan tier +- Joining to revenue models as the canonical user dimension +``` + +Fill in the domains that cover your most common questions first (typically Users, Activity, and Revenue). You can expand the index over time as you notice the Agent guessing at tables. + +Don't skip the **Important Notes** section at the bottom of the Skill. Documenting your standard filters (e.g., `where not is_internal_user`), your fully-qualified project path, your partition fields, and any plan or tier values prevents the Agent from accidentally fanning out joins, scanning entire partitioned tables, or returning numbers polluted by test accounts. + +After you complete this step, the Agent has a curated map from question to table and will consult it before writing any BigQuery SQL. + +## 3. Review the analysis-artifacts Skill + +The [`analysis-artifacts`](https://github.com/warpdotdev/oz-skills/blob/main/.agents/skills/analysis-artifacts/SKILL.md) Skill is workflow scaffolding. It tells the Agent how to structure a deep-dive analysis: plan first, save every material SQL query to `assets/queries/`, save visualizations to `assets/visualizations/`, and write a readable README with a Problem Statement, TL;DR, Cohorts Definition, per-step sections, and Key Takeaways. + +No customization is needed to start using it. When the Agent invokes it, you'll end up with a directory like: + +``` +analyses/ +└── 2026-04-ai-usage-by-os/ + ├── README.md + └── assets/ + ├── queries/ + │ └── ai_requests_by_os.sql + └── visualizations/ + ├── os_trend.py + └── os_trend.png +``` + +That structure is what makes the analysis shareable. A teammate can read the README, click through to any SQL file, and reproduce or extend the work. + +## 4. Ask a simple data question + +With both Skills in place, start with a concrete lookup prompt. This exercises `dbt-model-index` without pulling in the deep-dive workflow. + +Open an Agent conversation inside your dbt repo and ask: + +``` +How many unique users made AI requests yesterday? +``` + +The Agent will: + +1. Consult `dbt-model-index` to find the right activity table. +2. Write a BigQuery query, applying any standard filters you documented (e.g., excluding internal users). +3. Run the query via the `bq` CLI. +4. Return a single number along with the SQL it ran. + +Verify the result by reviewing the query. If it used the wrong table or skipped a standard filter, your `dbt-model-index` entries for that domain need more detail. Update the Skill and try again. + +## 5. Run a deep-dive analysis + +Now try a prompt that goes beyond a single lookup. The Agent recognizes this as a deep dive and invokes `analysis-artifacts`. + +``` +Tell me about any recent trends in AI usage across different operating systems in the last month. +``` + +The Agent will: + +1. Use `dbt-model-index` to resolve the right activity and OS dimensions. +2. Invoke `analysis-artifacts`, propose a plan, and wait for your approval. +3. Execute the plan step by step, saving queries and visualizations as artifacts. +4. Write a README summarizing the analysis end to end. + +The resulting README follows a consistent shape, roughly: + +```markdown +# AI usage trends by operating system (last 30 days) + +Author: Your Name +Date: 2026-04-22 + +## TL;DR +One or two sentences capturing the headline finding. + +## Problem Statement +What the analysis set out to answer and why. + +## Cohorts Definition +Explicit definition of the groups being compared, including tenure, +plan type, and observation windows. + +## Step 1: Baseline volume by OS +Narrative, embedded chart, and a link to the query in assets/queries/. + +## Step 2: Week-over-week trend +... + +## Key Takeaways +Bulleted summary of what was learned and any follow-up questions. +``` + +Commit the new `analyses/<name>/` directory to your repo so it's reviewable alongside your code. Anyone on the team can read it, verify the queries, or pick up where you left off. + +## Adapting to your stack + +Both Skills were written for BigQuery and dbt, but the pattern generalizes. Here's what to change: + +* **Non-BigQuery warehouse (Snowflake, Redshift, Databricks)** — Update the **Important Notes** section of `dbt-model-index/SKILL.md` with your warehouse's fully-qualified table reference format, partition or clustering conventions, and standard filters. Replace `bq` references with your warehouse's CLI (e.g., `snowsql`, `redshift-data`). +* **No dbt** — The `dbt-model-index` Skill works for any warehouse schema, not just dbt. Rename it if you like, and treat the entries as a map over raw tables, views, or your semantic layer. +* **Different modeling conventions** — Document your grain, tier or plan values, and internal-user filters explicitly in the Skill. Agents are good at following documented rules and bad at guessing them. + +The `analysis-artifacts` Skill is largely stack-agnostic. It structures outputs, not queries, so it works the same regardless of warehouse. + +## Next steps + +You installed two community Skills, customized the model index for your warehouse, and ran both a simple lookup and a full deep-dive analysis. + +**Extend to Slack.** Wire the same two Skills into an Oz cloud agent configured with your dbt repo, and your teammates can ask data questions by @-mentioning Oz in a Slack channel, without opening a terminal. The Agent clones the repo, picks up the Skills from `.agents/skills/`, and replies in-thread. See the [Slack integration docs](https://docs.warp.dev/agent-platform/cloud-agents/integrations/slack/) and [Skills as Agents](https://docs.warp.dev/agent-platform/cloud-agents/skills-as-agents/) for setup. + +Explore related guides and features: + +* [Trigger reusable actions with saved prompts](/guides/configuration/trigger-reusable-actions-with-saved-prompts/) — another reusable Agent primitive, useful for scaffolding frequent data questions +* [Create project rules](/guides/configuration/how-to-create-project-rules-for-an-existing-project-astro-typescript-tailwind/) — pair Skills with Rules to steer Agent behavior across your repo +* [Skills](https://docs.warp.dev/agent-platform/capabilities/skills/) — full reference on Skills, discovery, arguments, and slash-command invocation +* [warpdotdev/oz-skills](https://github.com/warpdotdev/oz-skills) — public repo with these two Skills and more diff --git a/src/content/docs/guides/configuration/how-to-sync-your-monorepos.mdx b/src/content/docs/guides/configuration/how-to-sync-your-monorepos.mdx new file mode 100644 index 0000000..a8edcfc --- /dev/null +++ b/src/content/docs/guides/configuration/how-to-sync-your-monorepos.mdx @@ -0,0 +1,75 @@ +--- +title: "How To: Sync Your Monorepos" +description: >- + Define global Rules in Warp to keep monorepo schemas, server types, and + client types automatically synchronized across repositories. +sidebar: + label: "Sync your monorepos" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +Learn how to use Warp’s Rules system to connect interrelated repositories and automate type updates across your stack. + +<VideoEmbed url="https://youtu.be/bndY6opaA7w?si=6zZWh4aB8f8kCD5F" /> + +--- + +## Intro + +This tutorial teaches you how to define **global Rules** in Warp so your coding agent understands how your projects relate to one another. + +By linking monorepos (e.g., server, client, and shared API schemas), Warp automatically updates types and schemas across repos when you make a change in one place. + +Although this example uses Warp’s internal repos, the same workflow applies to any multi-repo setup. + +--- + +## The Problem + +When projects are split into multiple repos — like backend, client, and shared schema — developers often forget to synchronize type changes manually. + +That’s error-prone and time-consuming. Warp solves this by teaching your **agent** the relationships between your repos through a global Rule. + +--- + +## The Rule Setup + +Describe each repository and its connection to the others. + +### Example Rule + +``` +We have three inter-related projects in ~/Repos: + +warp-internal (client-side application) + +warp-server (server application) + +warp-proto-apis (shared API schemas for each) + +When you update the schema types, push to git and update the installed types in the server and client by the commit hash. +``` +Once defined, Warp automatically follows these instructions when a schema file is changed. + +<Steps> + +1. #### When the schema updates — update server types + + `cd` into the server repository and run the appropriate commands to regenerate/update server-side types based on the changed schema. + +2. #### When the schema updates — update client types + + `cd` into the client repository and run the appropriate commands to regenerate/update client-side types so the client stays in sync with the schema changes. + +</Steps> + +--- + +:::tip +Benefits + +* Keeps your **schema, server, and client** perfectly in sync +* Reduces merge conflicts and version drift +* Saves manual steps when committing or deploying +::: diff --git a/src/content/docs/guides/configuration/how-to-use-agent-profiles-efficiently.mdx b/src/content/docs/guides/configuration/how-to-use-agent-profiles-efficiently.mdx new file mode 100644 index 0000000..2fdb7fb --- /dev/null +++ b/src/content/docs/guides/configuration/how-to-use-agent-profiles-efficiently.mdx @@ -0,0 +1,72 @@ +--- +title: "How To: Use Agent Profiles Efficiently" +description: >- + Compare Strategic and YOLO agent profiles side-by-side to choose the right + balance of planning, safety, and speed for your project. +sidebar: + label: "Use Agent Profiles efficiently" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Agent Profiles control how your coding agents behave in different contexts.\ +They define what the agent can read, plan, or execute — and how much autonomy it has. + +To show how profiles change workflow, we’ll build an NFL Predictor App using two profiles: + +* Strategic Agent +* YOLO Agent + +<VideoEmbed url="https://youtu.be/iD0R-8fY-tY?si=roCh6d78AuENAyFt" /> + +--- + +### Strategic Agent + +Base Model: GPT-5\ +Planning Model: Claude 4 Opus + +Configuration: + +* Apply code diffs → _agent decides_ +* Read files → _always allow_ +* Create plans → _always allow_ +* Execute commands → _ask first_ + +When run: + +1. The agent asks clarifying questions (e.g., _Do you want to scrape players and schedules?_) +2. Builds a detailed 14-step plan +3. Requests user input for environment variables + +It’s thorough and safe — but pauses often if you miss setup details. + +--- + +### YOLO Agent + +Configuration: + +* Apply code diffs → _always allow_ +* Read files → _always allow_ +* Create plans → _never_ +* Execute commands → _always allow_ + +This agent skips long planning.\ +It builds the project quickly, skipping over optional validation and focusing on essentials: + +* Data ingestion +* Player stats +* Scoring calculation + +It avoids brittle endpoints and produces a working dataset fast — though with fewer checks. + +--- + +### Comparing the Two + +| Trait | Strategic Agent | YOLO Agent | +| --------- | ------------------- | ------------------ | +| Planning | Detailed (14 steps) | Minimal (10 steps) | +| Safety | High | Low | +| Speed | Moderate | Very fast | +| Ideal For | Production projects | Quick prototypes | diff --git a/src/content/docs/guides/configuration/trigger-reusable-actions-with-saved-prompts.mdx b/src/content/docs/guides/configuration/trigger-reusable-actions-with-saved-prompts.mdx new file mode 100644 index 0000000..23617aa --- /dev/null +++ b/src/content/docs/guides/configuration/trigger-reusable-actions-with-saved-prompts.mdx @@ -0,0 +1,73 @@ +--- +title: Trigger Reusable Actions With Saved Prompts +description: >- + Save and share prompts in Warp Drive to automate commits, code reviews, and + PR creation across your team. +sidebar: + label: "Trigger reusable actions with Saved Prompts" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +<VideoEmbed url="https://www.youtube.com/watch?t=3s&v=pE15zjJmB4E" /> + +### 1. Automating Commits + +When working on a PR, instead of typing long commit messages, you can use a saved prompt. + +Warp’s agent: + +* Runs a `git diff` and summarizes the change +* Generates a clean commit message +* Pushes it automatically to your branch + +You can view the saved prompt in Warp Drive → Team Prompts, where it shows: + +* Who created it +* When it was last used +* How many times it’s been run + +Because it’s saved in your team drive, anyone can reuse it. + +--- + +### 2. Reviewing Code with Prompts + +Before creating a PR, you can run another saved prompt. + +This agent: + +* Reads your current branch +* Reviews the diffs +* Highlights logical or stylistic issues +* Suggests improvements + +Example output: + +> “Logic bug detected — potential race condition in async handler.” + +Warp automatically surfaces real issues before you even open a PR — saving time and reducing back-and-forth with reviewers. + +--- + +### 3. Opening a Pull Request Automatically + +Once your code looks clean, trigger your final saved prompt. + +Warp will: + +* Generate a PR title and description +* Push the branch +* Open the PR on GitHub +* Even link related issues if found in commit messages + +--- + +### 4. Sharing and Team Usage + +All saved prompts live in your Team Warp Drive, meaning: + +* Anyone can discover and run them +* You can parameterize or modify them +* Usage history and creator info are visible + +This makes it easy for teams to standardize common actions like code reviews, deployments, or build runs. diff --git a/src/content/docs/guides/devops/how-to-analyze-cloud-run-logs-gcloud.mdx b/src/content/docs/guides/devops/how-to-analyze-cloud-run-logs-gcloud.mdx new file mode 100644 index 0000000..3a08f43 --- /dev/null +++ b/src/content/docs/guides/devops/how-to-analyze-cloud-run-logs-gcloud.mdx @@ -0,0 +1,73 @@ +--- +title: "How to: Analyze Cloud Run Logs (gcloud)" +description: >- + Use Warp to pull, organize, and analyze Cloud Run production logs by + severity with natural language prompts and automated Python scripts. +sidebar: + label: "Analyze Cloud Run logs" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +Learn how to use Warp to retrieve, organize, and analyze production logs from your cloud servers — all with natural language prompts. + +<VideoEmbed url="https://youtu.be/GJ0NepZmmv8?si=MHhAVD2JeTLYc9rM" /> + +<Steps> + +1. #### Setting the Context + + Open Warp and enable **voice input** (optional) for hands-free prompting. + + :::note + Voice input is optional — only enable it if you prefer hands-free prompting. + ::: + + **Prompt** + + ``` + Use the warp-server-staging gcloud project and pull logs + for the last 10 minutes from the warp-server Cloud Run instance. + Organize them by info, warning, and error levels. + Create a histogram across message types, + and highlight the most concerning errors to investigate. + ``` + +2. #### Warp’s Agent in Action + + After you hit Enter: + + * Warp detects the command as an **Agent Mode** request. + * It gathers project context (`warp-server-staging`). + * Executes the necessary `gcloud` logging queries automatically. + * Writes retrieved data to a temporary file for processing. + +3. #### Automated Analysis + + Warp’s agent generates a **Python script** on the fly to: + + * Parse logs + * Count messages by severity + * Output summary metrics + + Example output: + + ``` + 1,000 log entries total + 980 info + 11 warning + 9 errors + ``` + + You can view or fast-forward execution, or stop the process at any point. + +4. #### Reviewing Results + + Warp outputs a readable histogram and highlights anomalies.\ + For example: + + > “Gemini AI error messages detected — worth reviewing.” + + You can expand each log group interactively or inspect the temporary Python code for debugging. + +</Steps> diff --git a/src/content/docs/guides/devops/how-to-create-a-production-ready-docker-setup.mdx b/src/content/docs/guides/devops/how-to-create-a-production-ready-docker-setup.mdx new file mode 100644 index 0000000..d6b224d --- /dev/null +++ b/src/content/docs/guides/devops/how-to-create-a-production-ready-docker-setup.mdx @@ -0,0 +1,57 @@ +--- +title: "How To: Create a Production Ready Docker Setup" +description: >- + Use Agents in Warp to generate optimized Dockerfiles, docker-compose + configs, and .dockerignore files for multi-stage production deployments. +sidebar: + label: "Create a production-ready Docker setup" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +Learn how to use Warp’s AI to automatically build a clean, multi-stage Docker setup for both development and production. + +<VideoEmbed url="https://youtu.be/zdQdEauSF6Q?si=CoOdDjiffiw-et6r" /> + +This tutorial shows how to create a **complete Docker environment** in minutes using Warp.\ +Warp’s AI can analyze your entire codebase, generate **Dockerfiles**, **.dockerignore**, and **docker-compose.yml** — all optimized for small image size and multi-service orchestration. + +Although this example uses a generic web app, the same pattern applies to **Python**, **Node.js**, **Go**, and other ecosystems. + +<Steps> + +1. #### The Challenge + + You’ve built your app and suddenly realize — it should have been containerized from the start.\ + Manually configuring Docker files, image sizes, and environment variables takes time and breaks flow. + +2. #### The Prompt + + Use this prompt inside Warp’s AI input: + + ``` + "Analyze my entire project directory structure, package files, and configuration to generate a complete production-ready Docker setup. I need: + + A multi-stage Dockerfile optimized for my specific language/framework with proper layer caching, security best practices, and minimal image size + A docker-compose.yml for both development and production environments with all necessary services, networks, volumes, and environment variable handling + A comprehensive .dockerignore file that excludes unnecessary files but keeps what's needed for the build + Startup scripts and health check configurations + Documentation explaining each Docker command and why specific choices were made + + Please detect my project type automatically and configure everything accordingly. Include comments explaining the optimization decisions." + + ``` + Warp will detect frameworks, infer services, and produce a ready-to-run setup. + +3. #### Review and Customize + + Warp outputs: + + * Optimized base images + * Cached build layers + * Correct dependency stages + * Unified environment management + + You can easily adjust service names or ports in the generated compose file. + +</Steps> diff --git a/src/content/docs/guides/devops/how-to-create-priority-matrix-for-database-optimization.mdx b/src/content/docs/guides/devops/how-to-create-priority-matrix-for-database-optimization.mdx new file mode 100644 index 0000000..cde53bd --- /dev/null +++ b/src/content/docs/guides/devops/how-to-create-priority-matrix-for-database-optimization.mdx @@ -0,0 +1,302 @@ +--- +title: "How To: Create Priority Matrix for Database Optimization" +description: >- + Prompt Warp to audit SQL queries, analyze execution plans, and generate a + priority matrix ranking database optimizations by impact and effort. +sidebar: + label: "Create a priority matrix for database optimization" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +Learn how to generate a data-driven optimization matrix that ranks database issues by impact, risk, and effort. + +<VideoEmbed url="https://youtu.be/VgE5wgtDSnk?si=ndvN2k86RguHAs4w" /> + +<Steps> + +1. #### Intro + + This tutorial teaches you how to prompt Warp to audit and optimize your **database performance** automatically. + + It analyzes SQL queries, identifies common inefficiencies, and generates a **priority matrix** for improvements. + +2. #### The Problem + + When you tell AI to “optimize a query,” that could mean _anything_ — faster, safer, or simpler.\ + Instead, use Warp to clarify intent and return measurable outcomes. + +3. #### The Prompt + + Paste this into Warp’s AI input: + + ```` + # **Comprehensive Database Query Analysis and Optimization Guide** + + This guide provides a structured, repeatable approach for analyzing, profiling, and optimizing database performance within your application. + + --- + + ## **PHASE 1: Query Discovery & Cataloging** + + ### **Step 1 — Identify All Queries** + Scan the entire codebase and locate every SQL or ORM-based query. This includes: + + - All **raw SQL queries**, including stored procedures + - **ORM-generated queries** (capture the actual SQL being produced) + - **Dynamic query builders** and their permutations + - **Background job queries** that may run at scale + - **Admin or reporting queries** that could lock tables + + ### **Step 2 — Document Key Details** + For each query discovered, record the following: + + - **File location and function name** + - **Frequency of execution** (per request, batch job, or cron schedule) + - **Typical data volume processed** + + --- + + ## **PHASE 2: Performance Analysis** + + For each identified query, generate and analyze a detailed **execution plan**. + + ### **Execution Plan Commands** + ```sql + -- PostgreSQL + EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON); + + -- MySQL + EXPLAIN FORMAT=JSON; + ``` + + ### **Extract the Following Metrics** + - Total execution time + - Rows examined vs. rows returned ratio + - Index usage (full table scans, index scans, seeks) + - Join methods (nested loop, hash, merge) + - Memory usage and temporary file creation + - Buffer pool hit ratio + + --- + + ## **PHASE 3: Identify Specific Problems** + + ### **1. N+1 Query Detection** + **Problem:** Loading users and their posts separately + **Found in:** `/api/users/controller.js:45` + **Impact:** 100 queries for 100 users instead of one batched query + + #### **Current Implementation** + ```js + const users = await db.query('SELECT * FROM users'); + for (const user of users) { + user.posts = await db.query('SELECT * FROM posts WHERE user_id = ?', [user.id]); + } + ``` + + #### **Optimized Version** + ```js + const usersWithPosts = await db.query(` + SELECT u.*, + COALESCE(json_agg(p.*) FILTER (WHERE p.id IS NOT NULL), '[]') AS posts + FROM users u + LEFT JOIN posts p ON p.user_id = u.id + GROUP BY u.id; + `); + ``` + + --- + + ### **2. Missing Index Analysis** + **Finding:** Full table scan on `orders` table (2M rows) + **Query:** + ```sql + SELECT * FROM orders WHERE status = 'pending' AND created_at > ?; + ``` + + **Recommendation:** + ```sql + CREATE INDEX idx_orders_status_created ON orders(status, created_at); + ``` + + **Impact:** Query time reduced from **3.2s → 0.045s** + + --- + + ### **3. Inefficient JOIN Patterns** + **Problem:** Queries join through unnecessary intermediate tables. + **Solution:** Simplify relationships using direct joins or indexed subqueries where possible. + + --- + + ### **4. Subquery Optimization** + **Inefficient Query:** + ```sql + SELECT * FROM products + WHERE price > (SELECT AVG(price) FROM products WHERE category_id = p.category_id); + ``` + + **Optimized (Using Window Function):** + ```sql + WITH product_stats AS ( + SELECT *, + AVG(price) OVER (PARTITION BY category_id) AS avg_category_price + FROM products + ) + SELECT * FROM product_stats WHERE price > avg_category_price; + ``` + + --- + + ## **PHASE 4: Advanced Optimizations** + + ### **Caching Strategies** + Use caching for: + - User-specific data with low update frequency + - Expensive aggregations that can be pre-computed + + #### **Implementation** + ```js + // Add caching layer with TTL + const getCachedOrQuery = async (key, query, ttl = 3600) => { + const cached = await redis.get(key); + if (cached) return JSON.parse(cached); + + const result = await db.query(query); + await redis.setex(key, ttl, JSON.stringify(result)); + return result; + }; + ``` + + --- + + ### **Recommended Connection Configuration** + ```json + { + "connectionLimit": 50, + "queueLimit": 100, + "acquireTimeout": 30000, + "waitForConnections": true, + "idleTimeout": 300000, + "enableKeepAlive": true, + "keepAliveInitialDelay": 10 + } + ``` + + --- + + ### **Batch Operation Optimization** + + **Problem:** Records are inserted one by one + **Found in:** `/jobs/import-data.js` + + **Current Implementation:** + 1000 individual `INSERT` statements + + **Optimized:** + ```sql + INSERT INTO users (name, email, created_at) VALUES + ($1, $2, $3), + ($4, $5, $6), + ... -- batch in groups of 1000 + ``` + + --- + + ### **Pagination Optimization** + ```sql + SELECT * FROM posts + WHERE created_at < $cursor + ORDER BY created_at DESC + LIMIT 20; + ``` + + --- + + ## **PHASE 5: Monitoring & Maintenance** + + ### **1. Slow Query Logging Setup** + + #### **PostgreSQL** + ```sql + ALTER SYSTEM SET log_min_duration_statement = '1000'; -- Log queries over 1s + ALTER SYSTEM SET log_statement = 'all'; + ALTER SYSTEM SET log_duration = on; + ``` + + #### **MySQL** + ```sql + SET GLOBAL slow_query_log = 'ON'; + SET GLOBAL long_query_time = 1; + SET GLOBAL log_output = 'TABLE'; + ``` + + --- + + ### **2. Query Performance Testing** + + ```js + describe('Query Performance', () => { + test('User listing should complete under 100ms', async () => { + const start = Date.now(); + await db.query('SELECT * FROM users LIMIT 1000'); + expect(Date.now() - start).toBeLessThan(100); + }); + }); + ``` + + --- + + ## **PHASE 6: Deliverables** + + ### **Deliverable Outputs** + - **Optimization Script:** A single SQL file with all index creations, ordered by performance impact. + - **Code Changes PR:** Includes all query optimizations with before/after comparison results. + + ### **Performance Report** + - Baseline metrics vs. optimized metrics + - Expected resource savings (CPU, memory, I/O) + - Risk assessment for each change + + ### **Monitoring Dashboard** + Define recurring queries to track query performance over time. + + --- + + ## **PRIORITY MATRIX** + + Rank each optimization by: + - **Impact:** Query frequency × time saved + - **Risk:** Low / Medium / High + - **Effort:** Quick fix / Moderate / Complex refactor + + > Focus on **high-impact**, **low-risk**, **low-effort** items first. + + --- + + ### **Summary** + This workflow ensures the AI: + 1. Systematically identifies all queries + 2. Analyzes them using database-specific profiling tools + 3. Provides **actionable, tested solutions** + 4. Considers the full application context + 5. Delivers **implementation-ready optimizations** + + ```` + Warp will locate all SQL usage, test each query, and score them using explain-plan data. + +4. #### Review the Matrix + + The output includes: + + * Query locations + * Performance metrics + * Recommended fixes + * A **graph** mapping impact vs effort + +</Steps> + +:::caution +A well-tuned database is the heart of your web stack — don’t skip it. +::: diff --git a/src/content/docs/guides/devops/how-to-generate-unit-and-security-tests-to-debug-faster.mdx b/src/content/docs/guides/devops/how-to-generate-unit-and-security-tests-to-debug-faster.mdx new file mode 100644 index 0000000..2c426e5 --- /dev/null +++ b/src/content/docs/guides/devops/how-to-generate-unit-and-security-tests-to-debug-faster.mdx @@ -0,0 +1,124 @@ +--- +title: "How to: Generate Unit and Security Tests to Debug Faster" +description: >- + Prompt Warp to generate comprehensive unit and security tests for REST APIs, + including SQL injection, XSS, and auth validation checks. +sidebar: + label: "Generate unit and security tests to debug faster" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +Learn how to prompt Warp’s AI to generate useful unit and security tests — helping you debug faster and deploy with confidence. + +<VideoEmbed url="https://youtu.be/YzZmrusN8Cw?si=64ZsLu6e76rv-nI6" /> + +--- + +<Steps> + +1. #### The Problem + + Building REST APIs involves a lot of overhead: validation, testing, and security.\ + Most “auto-generated tests” from AI end up generic and incomplete — leaving gaps in reliability. + + To solve this, Warp lets you run **precise, context-aware test generation** using better-structured prompts. + +2. #### The Prompt + + Paste this into Warp’s AI input: + + ```text title="prompt.txt" + After implementing this API code, generate comprehensive unit tests and security tests to verify everything works correctly and securely: + + 1. Unit tests for each function / method + + Core functionality + - Happy path with valid inputs -> expected output + - Each edge case (empty inputs, nulls, boundary values) + - Error handling for invalid inputs + - Return value types and structure + - Edge cases: empty strings, null/undefined, max values, special characters + + 2. SECURITY TESTS FOR EACH ENDPOINT + + For every API endpoint, create security tests that check: + + Input validation + Test with these malicious payloads in every user input field: + + SQL Injection: " ' OR '1' = '1', "1; DROP TABLE users--", "admin'--" + NoSQL Injection: {"$gt": ""}, {"$ne": null} + Command Injection: "; ls -la", "| whoami", "$(cat /etc/passwd)" + Path Traversal: "../../../etc/passwd", "..\..\..\windows\system32" + XSS: "<script>alert('XSS')</script>", "javascript:alert(1)" + XXE (for XML): "<!DOCTYPE foo [<!ENTITY xxe SYSTEM 'file:///etc/passwd'>]>" + + Authentication Tests: + - No token/credentials → Must return 401 + - Invalid token → Must return 401 + - Expired token → Must return 401 + - Valid token for wrong user → Must return 403 + - Token with insufficient permissions → Must return 403 + + Authorization Tests: + - User A trying to access User B's data → 403 + - Regular user accessing admin endpoints → 403 + - Deleted/disabled user token → 401 + - Verify all role-based access controls work + + Additional Security Checks: + - Rate limiting works (spam 100 requests → 429 response) + - Large payloads are rejected (>1MB unless specified) + - Sensitive data not exposed in errors + - Headers don't leak server info + - CORS properly configured + + 3. After running all tests, ensure: + ✓ All unit tests pass + ✓ 100% of functions have tests + ✓ All security tests pass + ✓ No SQL/NoSQL injection vulnerabilities + ✓ Authentication is properly enforced + ✓ Authorization rules are working + ✓ Input validation catches malicious data + ✓ Error messages don't expose sensitive info + + 4. Output Format + + Generate 2 test files: + 1. Unit_tests.[ext] - all functional tests + 2. security_tests.[ext] - all security tests + + Use simple assertions that clearly show: + - What is being tested + - What the expected behavior is + - Why this test matters + + Keep these tests simple and focused - each test should verify ONE thing + ``` + +3. #### Add to Rules File + + Once you’ve validated the prompt, add it to your Warp Rules file so Warp can automatically reuse it. + + ``` + Name: Run tests after writing + Rule: run pytest mapp/tests to validate if the code you inserted works + ``` + + Warp will then run these tests as a source of truth — deciding whether new AI-generated code is safe to merge or deploy. + +4. #### Recap + + :::tip + You’ve learned how to: + + * Prompt for **specific test coverage** + * Automate your **unit and security tests** + * Use Warp’s **Rules** feature for validation + + Small change in prompt structure — big jump in reliability. + ::: + +</Steps> diff --git a/src/content/docs/guides/devops/how-to-prevent-secrets-from-leaking.mdx b/src/content/docs/guides/devops/how-to-prevent-secrets-from-leaking.mdx new file mode 100644 index 0000000..0d3f208 --- /dev/null +++ b/src/content/docs/guides/devops/how-to-prevent-secrets-from-leaking.mdx @@ -0,0 +1,49 @@ +--- +title: "How To: Prevent Secrets from Leaking" +description: >- + Use Warp Rules and built-in secret reduction to prevent API keys and + credentials from leaking in agent output, demos, and shared sessions. +sidebar: + label: "Prevent secrets from leaking" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +Learn how to safeguard credentials and sensitive data using Warp’s secret-reduction and Rule system. + +<VideoEmbed url="https://youtu.be/2ECPFKtQpVk?si=HHw14Tqj-QyHeByX" /> + +This tutorial shows how to use Warp’s **Rules** to prevent AI agents or collaborators from exposing sensitive information while coding or sharing output. Whether you’re pair-programming, streaming, or reviewing code, Warp can automatically redact secrets before they’re ever seen by an agent. + +<Steps> + +1. #### The Problem + + AI assistants often echo API keys, tokens, or credentials in generated code blocks.\ + When collaborating or screen-sharing, that can expose secrets publicly. + +2. #### The Rule Setup + + Define a simple Rule in Warp that instructs the agent to **never display secrets** in outputs or commands. + + ``` + Rule: Protect Secrets + Behavior: + - Never include or reveal secrets when generating code or commands. + - Automatically redact sensitive strings before showing output. + ``` + :::note + Enable Warp’s built-in Secret Reduction: + + Settings → AI → Enable Secret Reduction + + This automatically masks sensitive values before the agent or output logs can access them. + ::: + +3. #### Benefits + + * Protects API keys and credentials from exposure + * Keeps live streams and demos safe + * Works seamlessly with pair-programming or AI debugging + +</Steps> diff --git a/src/content/docs/guides/devops/how-to-write-sql-commands-inside-a-postgres-repl.mdx b/src/content/docs/guides/devops/how-to-write-sql-commands-inside-a-postgres-repl.mdx new file mode 100644 index 0000000..cc6965c --- /dev/null +++ b/src/content/docs/guides/devops/how-to-write-sql-commands-inside-a-postgres-repl.mdx @@ -0,0 +1,166 @@ +--- +title: "How To: Write SQL Commands inside a Postgres REPL" +description: >- + Use Agents in Warp inside a Postgres REPL to translate natural language into + SQL queries — works with Node.js, Python, and MySQL too. +sidebar: + label: "Write SQL commands inside a Postgres REPL" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +:::note +This tutorial teaches you how to use **Warp’s AI input** to run natural-language prompts inside an interactive **Postgres REPL**, turning plain English into SQL commands.\ +\ +Although the example uses **PostgreSQL**, the same workflow applies to **Node.js**, **Python**, **MySQL**, and other interactive shells. +::: + +<VideoEmbed url="https://www.youtube.com/watch?v=guXQSMq_Yss" /> + +--- + +### 🧠 Overview + +You’ll learn how to: + +* Start a Postgres REPL in Warp. +* Use **Command + I** (or **Ctrl + I**) to open Warp’s AI input. +* Speak or type natural-language requests and let Warp translate them into SQL. +* Run the generated queries directly inside your REPL session. + +<Steps> + +1. #### Open a Postgres REPL in Warp + + Open Warp and connect to your Postgres database (or a test instance): + + ```bash + psql -U postgres -d my_database + ``` + + You’ll enter the interactive `psql` prompt, where you normally type SQL commands. + +2. #### Invoke Warp’s AI Input + + Inside the running REPL, press: + + ``` + Command + I (macOS) + Ctrl + I (Windows/Linux) + ``` + + This opens the **Generate Input** box. + + You can **type or speak** in plain English — Warp will translate your request into valid SQL or shell syntax, depending on the REPL you’re in. + +3. #### Ask Warp in Natural Language + + Start with a simple request: + + ``` + Show me all tables. + ``` + + Warp translates this to the Postgres command: + + ```sql + \dt + ``` + + Then try a more specific query, as shown in the video: + + ``` + Show me our users table and our teams table. + ``` + + Warp generates: + + ```sql + SELECT * FROM users; + SELECT * FROM teams; + ``` + + You can run both within your REPL to display the tables. + +4. #### Observe How Warp Learns from Context + + As you continue issuing prompts, Warp’s AI agent **learns the structure of your database** by observing what’s printed in the REPL output. + + This means you can ask progressively more complex questions, and Warp will tailor the SQL accordingly. + + ``` + Show me all of the users who have joined Warp in the last 90 days from public email accounts + (like Gmail, Yahoo, Hotmail) and are on teams of more than two people. + ``` + + Warp generates a multi-clause SQL query such as: + + ```sql + SELECT * + FROM users + WHERE email LIKE '%gmail.com%' + OR email LIKE '%yahoo.com%' + OR email LIKE '%hotmail.com%' + AND joined_at > NOW() - INTERVAL '90 days' + AND team_size > 2; + ``` + + Running this query in `psql` filters users accordingly. + +5. #### Apply the Same Workflow to Other REPLs + + This feature works **not just in Postgres** but also in: + + * Node.js + * Python + * MySQL + * GDB (GNU Debugger) + + For any of these environments: + + 1. Launch the REPL inside Warp. + 2. Press **Command + I** to bring up AI input. + 3. Describe what you want in natural language. + 4. Warp translates it into the correct syntax for that environment. + + :::note + Warp automatically detects the active REPL, so you don’t need to specify “SQL” or “Python” — it knows which language to generate. + ::: + +6. #### Experiment and Iterate + + Try varying your natural-language prompts: + + ``` + List all databases. + ``` + + ```sql + \l + ``` + + ``` + Count how many users signed up this month. + ``` + + ```sql + SELECT COUNT(*) FROM users WHERE joined_at > date_trunc('month', NOW()); + ``` + + The more you experiment, the more context Warp gathers, improving its translations. + +</Steps> + +--- + +### 🏁 Key Takeaways + +* **Command + I** activates Warp’s AI input within any interactive shell. +* Warp understands natural language and produces valid commands for the current REPL. +* It **learns from context** — subsequent prompts become more accurate. +* Works beyond Postgres: Node, Python, MySQL, and others. +* A fast way to query or explore systems without memorizing syntax. + +:::tip +Next time you’re stuck remembering a command in Postgres or Python, hit **Command + I** and just ask Warp in plain English. +::: diff --git a/src/content/docs/guides/devops/improve-your-kubernetes-workflow-kubectl-helm.mdx b/src/content/docs/guides/devops/improve-your-kubernetes-workflow-kubectl-helm.mdx new file mode 100644 index 0000000..956a65b --- /dev/null +++ b/src/content/docs/guides/devops/improve-your-kubernetes-workflow-kubectl-helm.mdx @@ -0,0 +1,92 @@ +--- +title: Improve Your Kubernetes Workflow (kubectl + helm) +description: >- + Streamline kubectl and Helm workflows with Warp's AI assistance, active + suggestions, custom workflows, and synchronized panes. +sidebar: + label: "Improve your Kubernetes workflow" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +Discover how Warp’s modern terminal features streamline Kubernetes workflows through AI assistance, automation, and intuitive design. + +<VideoEmbed url="https://www.youtube.com/watch?v=64TECXZiFb0" /> + +## Overview + +This guide covers 6 key Warp features that enhance Kubernetes productivity: + +<Steps> + +1. #### AI Integration in the Terminal + + Warp’s **Agent Mode** (`Cmd + I`) lets you run complex Kubernetes operations with plain-English prompts. + + **Examples** + + ``` + When does my wildcard TLS certificate expire? + ``` + + Warp auto-detects namespaces, runs `kubectl` commands, and outputs expiration details. + + ``` + Generate a command to identify all pods running as root across all namespaces. + ``` + + Warp builds and runs the corresponding `kubectl` + `grep` query, returning a security report. + + :::note + Ideal for on-the-fly debugging or compliance checks without leaving your terminal. + ::: + +2. #### Building AI-Aided Context + + You can attach any command’s output as context for follow-up prompts.\ + For instance, right-click log output → “Attach as Agent Context,” then run: + + ``` + I’m sending anonymous usage data in Traefik. How can I disable it? + ``` + + Warp detects the Helm chart and outputs the required YAML config to disable stats reporting. + +3. #### Active AI Suggestions + + Warp automatically suggests next actions.\ + Examples of suggested actions: + + * After `kubectl describe pod` it might propose: + + > “Check the logs of this pod.” + * When running `sudo apt update` it detects available upgrades and offers: + + > “Run sudo apt upgrade to update packages.” + +4. #### Custom Workflows + + Create reusable, parameterized commands for common operations like: + + ```bash + helm upgrade <chart> --namespace <namespace> -f <values.yaml> + ``` + Accessible from the **Command Palette (`Cmd + P`)**, workflows make repetitive Kubernetes tasks fast and standardized. + +5. #### Synchronized Panes and Tabs + + Link multiple terminal panes or tabs (e.g., master + worker nodes).\ + When synchronization is active, running: + + ```bash + sudo apt update + ``` + + executes simultaneously across all linked sessions. + +6. #### Modern Text Editing + + Warp supports **click-to-edit** for commands — no more arrow key gymnastics.\ + Hovering shows inline **tooltips** explaining flags and subcommands (e.g., Helm, kubectl, etc.), with autocompletions for 400+ CLI tools. + +</Steps> diff --git a/src/content/docs/guides/external-tools/context7-mcp-update-astro-project-with-best-practices.mdx b/src/content/docs/guides/external-tools/context7-mcp-update-astro-project-with-best-practices.mdx new file mode 100644 index 0000000..d2d513e --- /dev/null +++ b/src/content/docs/guides/external-tools/context7-mcp-update-astro-project-with-best-practices.mdx @@ -0,0 +1,80 @@ +--- +title: "Context7 MCP: Update Astro Project with Best Practices" +description: >- + Use the Context7 MCP server to give Warp agents real-time access to + framework documentation for automated project upgrades. +sidebar: + label: "Context7 MCP: Update Astro project with best practices" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +:::note +This tutorial shows how the **Context7 MCP Server** gives Warp agents real‑time access to documentation for upgrading frameworks and codebases automatically. +::: + +<VideoEmbed url="https://youtu.be/rrxfS9u1XRA?si=X2CBWW1PD3M8IuFr&t=369" /> + +--- + +## 🧠 Overview + +The **Context7 MCP Server** lets Warp fetch live documentation from across the web.\ +\ +In the example, the agent updates an older **Astro** project to align with the latest version (Astro 5). + +--- + +<Steps> + +1. #### Add the Context7 Server + + * Open Warp’s **MCP Panel** via the Command Palette. + * Add the **Context7 JSON config** and click **Save**. + + ```json + { + "Context7": { + "command": "npx", + "args": [ + "-y", + "@upstash/context7-mcp" + ], + "env": {}, + "working_directory": null + } + } + ``` + + * This enables the endpoint `getLibraryDocs`, which retrieves live documentation directly from the official sources. + +2. #### Run the Update Prompt + + The developer issues this prompt: + + ``` + Create a new git branch called update and in that branch update this Astro project to follow all the latest best practices based on all Astro and developer documentation. + ``` + +3. #### Review the Automatic Code Changes + + The transcript shows that Warp automatically: + + * Updates Tailwind import syntax + * Improves TypeScript configuration + * Optimizes build settings + * Enhances accessibility rules + + These edits happen across multiple files — without manually searching docs or changelogs. + +4. #### Best Use Cases + + * Migrating old Astro, React, or Vue projects + * Refreshing codebases to reflect recent standards + * Saving time otherwise spent reading version notes + +</Steps> + +:::tip +Context7 MCP automates documentation lookups — letting Warp update your project intelligently based on live references. +::: diff --git a/src/content/docs/guides/external-tools/figma-remote-mcp-create-a-website-from-a-figma-file-from-scratch.mdx b/src/content/docs/guides/external-tools/figma-remote-mcp-create-a-website-from-a-figma-file-from-scratch.mdx new file mode 100644 index 0000000..ae54a50 --- /dev/null +++ b/src/content/docs/guides/external-tools/figma-remote-mcp-create-a-website-from-a-figma-file-from-scratch.mdx @@ -0,0 +1,115 @@ +--- +title: "Figma Remote MCP: Create a Website from a Figma File from Scratch" +description: >- + Connect Warp to Figma's remote MCP server via OAuth and generate front-end + code directly from your design files. +sidebar: + label: "Figma Remote MCP: Create a website from a Figma file from scratch" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +Learn how to connect Warp to Figma’s remote MCP server to generate code directly from your design files — complete with screenshots, metadata, and design system context. + +<VideoEmbed url="https://youtu.be/PsM_Y8Pt-1Q?si=wYT-lXf-FYUizrEy" /> + +--- + +## Overview + +This guide covers how to: + +* Connect Warp to the **remote Figma MCP server** +* Log in securely using OAuth +* Use the server to pull live context (components, variables, and assets) from your Figma designs +* Generate front-end code based on your UI files +* Iterate and refine output directly in Warp + +--- + +<Steps> + +1. #### What Is a Remote MCP Server? + + A **remote MCP server** runs outside your local machine — Warp connects to it through a secure network call.\ + \ + This means you don’t have to manage processes, ports, or tokens manually. Warp handles setup, authentication, and communication for you. + +2. #### Connect Figma MCP to Warp + + * Copy the Figma MCP configuration JSON + + ``` + { + "Figma": { + "url": "https://mcp.figma.com/mcp" + } + } + ``` + + * In Warp, paste the JSON — Warp will automatically open an OAuth login window. + * Log in once with your **Figma account** credentials. + + :::note + You will need a Figma Dev account for this to work. + ::: + +3. #### What the Figma MCP Server Provides + + Once connected, the server enables Warp’s AI to understand your design context by fetching: + + | Type | Description | + | -------------------------------- | -------------------------------------------------------------------- | + | **`get_screenshot`** | Helps the AI visualize layout and relationships between elements. | + | **`create_design_system_rules`** | Components, variables, and styles for consistent, reusable code. | + | **`get_code`** | Extracts code from your Figma design for direct use in projects. | + | **`get_metadata`** | Includes text, images, and layer names for more realistic mock data. | + +4. #### Generate a Website from a Figma File + + Basic flow: + + * Copy your **Figma file link**: + * Right-click → _Copy / Paste As → Copy Link to Selection_ + * In Warp, paste a prompt to create a website based on that design. + + Prompt: + + ``` + Create a website from this Figma file: <LINK HERE> + Follow the design layout and use these guidelines: + - Match spacing and typography from the design + - Use Tailwind CSS and TypeScript + - Make components reusable + ``` + Warp uses the Figma MCP server to pull all necessary context and begin generating code diffs. + +5. #### Iterating on Output + + * In under five minutes, Warp generates a working site structure based on the Figma layout. + * Missing assets (e.g., logos or images) are automatically referenced in an `assets/` folder. + * Warp prompts you to add any missing files before continuing. + +6. #### Persistent Input Feature + + Warp’s **persistent input** allows mid-process updates.\ + If you forget an image (e.g., the Misho logo), simply upload it and notify Warp: + + ``` + I’ve uploaded the Misho logo to the assets folder. + ``` + + Warp will automatically detect and use it during the same generation session. + +7. #### Recap + + * Warp now supports **remote MCP servers** for Figma (and others like GitHub, Sentry, and Linear). + * OAuth login streamlines setup and removes manual token handling. + * The Figma MCP integration enables rapid, context-aware code generation. + * Persistent input and real-time iteration make design-to-code workflows seamless. + + :::tip + In under 20 minutes, you can go from Figma design to a functioning website — all powered by Warp’s AI coding environment. + ::: + +</Steps> diff --git a/src/content/docs/guides/external-tools/github-mcp-summarizing-open-prs-and-creating-gh-issues.mdx b/src/content/docs/guides/external-tools/github-mcp-summarizing-open-prs-and-creating-gh-issues.mdx new file mode 100644 index 0000000..20ec8f5 --- /dev/null +++ b/src/content/docs/guides/external-tools/github-mcp-summarizing-open-prs-and-creating-gh-issues.mdx @@ -0,0 +1,69 @@ +--- +title: "Github MCP: Summarizing Open PRs & Creating GH Issues" +description: >- + Connect the GitHub MCP server to Warp to summarize open PRs, create issues + from TODO comments, and automate repo management. +sidebar: + label: "GitHub MCP: Summarize open PRs and create GitHub issues" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +<VideoEmbed url="https://youtu.be/rrxfS9u1XRA?si=wDU42iXPhGlVn2RM&t=30" /> + +The GitHub MCP Server lets Warp agents read, write, and automate tasks in your GitHub repositories directly — no manual tab-switching required. + +--- + +### 2. Setup + +#### Step 1. Get a GitHub Personal Access Token + +1. Go to **GitHub → Settings → Developer Settings → Personal Access Tokens** +2. Create a new token and enable: + * ✅ `repo` + * ✅ `read:user` + +--- + +#### Step 2. Add the Server in Warp + +1. Open the **MCP Panel** via Command Palette (`Cmd + P`) +2. Click **Add Server** +3. Paste in your JSON config and the access token +4. Save — and you’ll see the available endpoints immediately + +--- + +### 3. Workflow 1 — Summarize All Open PRs + +Use Warp’s agent to summarize pull requests: + +Behind the scenes, the MCP server: + +* Lists PRs +* Fetches comments and reviews +* Compiles summaries with clickable links + +Perfect for daily PR triage or stand-ups. + +--- + +### 4. Workflow 2 — Create GitHub Issues from TODOs + +Use a saved prompt to automate issue creation. + +Warp: + +1. Scans your codebase for TODO comments +2. Calls `create_issue` for each one via MCP +3. Generates a linked list of new issues + +This turns scattered notes into trackable tickets instantly. + +--- + +### 5. Why It’s Useful + +* Save 20–30 minutes per session +* Keep repos synchronized automatically +* Enable PR summaries, issue tracking, and automation — all inside Warp. diff --git a/src/content/docs/guides/external-tools/how-to-set-up-claude-code.mdx b/src/content/docs/guides/external-tools/how-to-set-up-claude-code.mdx new file mode 100644 index 0000000..f4b0044 --- /dev/null +++ b/src/content/docs/guides/external-tools/how-to-set-up-claude-code.mdx @@ -0,0 +1,141 @@ +--- +title: How to set up Claude Code +description: >- + Set up Claude Code in Warp, configure it for your project, and learn + productivity tips — from voice prompting to visual code review. +sidebar: + label: "Set up Claude Code" +--- + +Claude Code is Anthropic's AI coding agent. It reads your codebase, writes and edits code, runs commands, and handles complex refactors using natural language prompts. This guide takes you from zero to a working Claude Code session in Warp in about 5 minutes, then shows you how to get the most out of it. + +## Prerequisites + +* **A Claude account with CLI access** — Claude Code requires a paid plan or API credits. See [Claude Code requirements](https://docs.anthropic.com/en/docs/claude-code/setup) for eligible plans. +* **macOS 13+, Windows 10+, or Ubuntu 20.04+** — See [Claude Code system requirements](https://docs.anthropic.com/en/docs/claude-code/setup) for full platform details. +* **Git** — Claude Code works best inside a Git repository. On Windows, [Git for Windows](https://git-scm.com) is required. + +## 1. Install Claude Code + +Follow Anthropic's [official installation guide](https://docs.anthropic.com/en/docs/claude-code/quickstart) to install Claude Code. The native installer (recommended) requires no dependencies and auto-updates in the background. + +When you launch Claude Code inside Warp, Warp auto-detects the agent session and surfaces integrated controls, including rich input, code review, vertical tab metadata, and more. + +## 2. Authenticate + +The first time you run Claude Code, it opens your browser for login. + +```bash +claude +``` + +Sign in with your Claude account. Once authenticated, the token is stored locally and you won't need to log in again. + +For headless environments or CI/CD, set an API key instead: + +```bash +export ANTHROPIC_API_KEY=YOUR_API_KEY +``` + +## 3. Start your first session + +Navigate to any project directory and launch Claude Code: + +```bash +cd ~/your-project +claude +``` + +Try giving it a task, for example: + +``` +Explain the architecture of this project +``` + +Or something more hands-on: + +``` +Add input validation to the user registration endpoint +``` + +Claude Code will find the relevant files, show you the proposed changes, and ask for confirmation before modifying anything. + +## 4. Configure for your project + +Create a `CLAUDE.md` file at your project root to teach Claude Code your project's conventions. Claude Code reads this file at the start of every session. + +```markdown +# My Project + +## Stack +- Backend: Python 3.12, FastAPI, SQLAlchemy +- Frontend: React, TypeScript, Vite +- Database: PostgreSQL 16 + +## Commands +- `npm run dev` starts the dev server +- `pytest -v` runs the test suite +- `npm run lint` checks code style + +## Conventions +- Use async/await for all database operations +- Type hints on all function signatures +- ESM imports only (no require()) +``` + +This prevents Claude Code from guessing your conventions and ensures it follows your team's standards from the first prompt. + +## 5. Choose a model and permissions + +Claude Code uses the latest Claude model by default. To use a specific model: + +```bash +claude --model MODEL_NAME +``` + +By default, Claude Code asks for permission before every file write and command execution. You can pre-approve safe operations in `.claude/settings.json`: + +```json +{ + "permissions": { + "allow": [ + "Read", + "Glob", + "Grep", + "Bash(pytest*)", + "Bash(npm run lint)" + ] + } +} +``` + +This lets Claude read files and run your test/lint commands without prompting, while still asking before writing files. + +## 6. Set up agent notifications + +Warp supports agent notifications for Claude Code through a plugin. When you run Claude Code in Warp without the plugin installed, a notification chip appears offering one-click installation. Once installed, Warp surfaces in-app and desktop alerts when Claude Code needs your input. + +For manual installation steps, troubleshooting, and SSH/remote setup, see [Claude Code in Warp (docs)](/agent-platform/cli-agents/claude-code/#setting-up-notifications). + +## Productivity tips + +* **Use voice to prompt Claude Code** — Instead of typing complex instructions, dictate them. Warp supports [voice transcription](/agent-platform/local-agents/interacting-with-agents/voice/) that works with any CLI agent, including Claude Code. Press the microphone icon or the `fn` key to start recording. +* **Attach images as context** — Paste screenshots of bug reports, design mockups, or error messages directly into your prompt. Warp's [images as context](/agent-platform/local-agents/agent-context/images-as-context/) feature lets Claude Code see what you see. +* **Review diffs visually** — After Claude Code makes changes, open Warp's [Code Review panel](/code/code-review/) (`⌘+Shift++`) to see a visual diff of every file changed. You can leave inline comments and send them back to Claude Code for corrections. +* **Run multiple Claude Code sessions in parallel** — Use [vertical tabs](/terminal/windows/vertical-tabs/) to run different Claude Code tasks side by side, one session fixing bugs while another writes tests. Each tab shows which agent is running and its current status. +* **Compose richer prompts** — Press `Ctrl+G` to open Warp's rich input editor for Claude Code. This gives you a full text editor experience for composing prompts — click to position your cursor, select text, and edit naturally instead of navigating with arrow keys. + +{/* If a standalone summary feels valuable, add a ## Recap heading above this paragraph. */} + +## Next steps + +You installed Claude Code, authenticated, started your first session, configured it for your project, and learned the key productivity features that make it faster to use in Warp. + +Explore related guides and features: +* [Set up Codex CLI](/guides/external-tools/how-to-set-up-codex-cli/) to run a second agent alongside Claude Code +* [How to review AI-generated code](/guides/agent-workflows/how-to-review-ai-generated-code/) — a structured workflow for reviewing and refining agent output +* [Run multiple agents at once](/guides/agent-workflows/how-to-run-multiple-ai-coding-agents/) — use Claude Code and Codex side by side +* [Claude Code documentation](https://docs.anthropic.com/en/docs/claude-code/quickstart) — Anthropic's official reference +* [Claude Code in Warp](https://warp.dev/agents/claude-code) — overview of Claude Code support in Warp +* [Claude Code in Warp (docs)](/agent-platform/cli-agents/claude-code/) — full reference for Claude Code's Warp integration, including notification setup +* [Third-party CLI agents](/agent-platform/cli-agents/overview/) — all supported agents and Warp's universal agent features diff --git a/src/content/docs/guides/external-tools/how-to-set-up-codex-cli.mdx b/src/content/docs/guides/external-tools/how-to-set-up-codex-cli.mdx new file mode 100644 index 0000000..6ea6efa --- /dev/null +++ b/src/content/docs/guides/external-tools/how-to-set-up-codex-cli.mdx @@ -0,0 +1,138 @@ +--- +title: How to set up Codex CLI +description: >- + Set up OpenAI's Codex CLI in Warp, configure it for your project, and learn + productivity tips for faster AI-assisted coding workflows in Warp. +sidebar: + label: "Set up Codex CLI" +--- + +Codex CLI is OpenAI's open-source coding agent. It reads your codebase, edits files, and executes commands from natural language prompts. This guide takes you from installation to a working Codex session in Warp in about 5 minutes, then shows you how to get the most out of it. + +## Prerequisites + +* **A ChatGPT account with Codex access** — Included with paid ChatGPT plans, or use an OpenAI API key. See [Codex CLI documentation](https://developers.openai.com/codex/cli/) for eligible plans. +* **Node.js 18+** (for npm install) or **Homebrew** (for macOS) — Choose your preferred package manager. +* **macOS or Linux** — Windows support is experimental; for the best Windows experience, use Codex in a WSL workspace. + +## 1. Install Codex CLI + +Install Codex CLI globally with npm or Homebrew: + +**npm:** + +```bash +npm install -g @openai/codex +``` + +**Homebrew (macOS):** + +```bash +brew install codex +``` + +Verify installation: + +```bash +codex --version +``` + +You can also download platform-specific binaries directly from the [GitHub releases](https://github.com/openai/codex/releases). + +## 2. Authenticate + +Run Codex for the first time: + +```bash +codex +``` + +Select **Sign in with ChatGPT** and authenticate with your ChatGPT account (recommended). Your Codex usage is included in your ChatGPT plan. + +For API key authentication (useful for CI/CD or automation): + +```bash +export OPENAI_API_KEY=YOUR_API_KEY +``` + +## 3. Start your first session + +Navigate to a project directory and launch Codex: + +```bash +cd ~/your-project +codex +``` + +Codex starts an interactive terminal session. Try giving it a task, for example: + +``` +Explain the structure of this project +``` + +Or something more hands-on: + +``` +Add error handling to the database connection module +``` + +Codex will read the relevant files, propose changes, and ask for your confirmation before modifying anything. You can review changes in a diff view and accept or reject each one. + +## 4. Configure model and approval mode + +Switch between available models during a session with the `/model` command. See [Codex CLI documentation](https://developers.openai.com/codex/cli/) for the current model list. + +Codex has three [approval modes](https://developers.openai.com/codex/cli/features#approval-modes) that control how much autonomy it has. +* **Auto** (the default) lets Codex read, edit, and run commands within your working directory but asks before anything outside that scope. +* **Read-only** keeps Codex consultative +* **Full Access** grants broader autonomy including network access. + +Use `/permissions` inside a session to switch modes as your comfort level changes. + +## 5. Customize with a configuration file + +Create a `codex.md` or `AGENTS.md` file at your project root to teach Codex your project's conventions: + +```markdown +# My Project + +## Stack +- Backend: Node.js, Express, TypeScript +- Database: PostgreSQL with Prisma ORM +- Testing: Vitest for unit tests, Playwright for e2e + +## Conventions +- Use ESM imports (no require()) +- All API endpoints need Zod input validation +- Run `npm test` before committing +``` + +Codex reads this file at the start of every session and follows your conventions automatically. + +:::note +Warp supports agent notifications for Codex. Add `notification_condition = "always"` under `[tui]` in `~/.codex/config.toml` and restart Codex. See [Codex in Warp (docs)](/agent-platform/cli-agents/codex/#setting-up-notifications) for details. If the config isn't set, Warp displays a setup chip in the terminal. +::: + +## Productivity tips + +* **Use voice to prompt Codex** — Dictate complex instructions instead of typing them. Warp supports [voice transcription](/agent-platform/local-agents/interacting-with-agents/voice/) that works with any CLI agent, including Codex. +* **Attach images as context** — Paste screenshots of bugs, designs, or error messages into your prompt. Warp's [images as context](/agent-platform/local-agents/agent-context/images-as-context/) feature lets Codex see what you see. +* **Review diffs visually** — After Codex makes changes, open Warp's [Code Review panel](/code/code-review/) (`⌘+Shift++`) to see a visual diff. You can leave inline comments and send them back to Codex for corrections. +* **Run Codex alongside Claude Code** — Use [vertical tabs](/terminal/windows/vertical-tabs/) to run Claude Code and Codex side by side on the same task. Compare their approaches and pick the best output, or combine elements from both. +* **Compose richer prompts** — Press `Ctrl+G` to open Warp's rich input editor for Codex, giving you a full text editor experience instead of raw CLI input. + +{/* If a standalone summary feels valuable, add a ## Recap heading above this paragraph. */} + +## Next steps + +You installed Codex CLI, authenticated, started your first session, and configured it for your project. Codex is now set up as a working AI coding agent in Warp. + +Explore related guides and features: + +* [Set up Claude Code](/guides/external-tools/how-to-set-up-claude-code/) to run a second agent alongside Codex +* [How to review AI-generated code](/guides/agent-workflows/how-to-review-ai-generated-code/) — a structured workflow for reviewing agent output +* [Run multiple agents at once](/guides/agent-workflows/how-to-run-multiple-ai-coding-agents/) — use Codex and Claude Code side by side +* [Codex CLI documentation](https://developers.openai.com/codex/cli/) — OpenAI's official reference +* [Codex in Warp](https://warp.dev/agents/codex) — overview of Codex support in Warp +* [Codex in Warp (docs)](/agent-platform/cli-agents/codex/) — full reference for Codex's Warp integration, including notification setup +* [Third-party CLI agents](/agent-platform/cli-agents/overview/) — all supported agents and Warp's universal agent features diff --git a/src/content/docs/guides/external-tools/how-to-set-up-gemini-cli.mdx b/src/content/docs/guides/external-tools/how-to-set-up-gemini-cli.mdx new file mode 100644 index 0000000..6be725a --- /dev/null +++ b/src/content/docs/guides/external-tools/how-to-set-up-gemini-cli.mdx @@ -0,0 +1,154 @@ +--- +title: How to set up Gemini CLI +description: >- + Set up Google's Gemini CLI in Warp, configure it for your project, and learn + productivity tips for faster AI-assisted coding workflows. +sidebar: + label: "Set up Gemini CLI" +--- + +Gemini CLI is Google's open-source coding agent. It brings Gemini directly into your terminal with built-in tools for file operations, shell commands, web search, and MCP support. This guide takes you from installation to a working Gemini CLI session in Warp in about 5 minutes, then shows you how to get the most out of it. + +## Prerequisites + +* **A Google account** — Gemini CLI's free tier includes 60 requests per minute and 1,000 requests per day with a personal Google account. Alternatively, use a Gemini API key or Vertex AI. See the [Gemini CLI authentication guide](https://geminicli.com/docs/get-started/authentication/) for all options. +* **Node.js 20+** — Required for installation. Check with `node -v`. +* **macOS, Linux, or Windows** — See [Gemini CLI system requirements](https://geminicli.com/docs/get-started/installation/) for recommended specifications. + +## 1. Install Gemini CLI + +Follow Google's [official installation guide](https://geminicli.com/docs/get-started/installation/) to install Gemini CLI. The two most common methods: + +**npm:** + +```bash +npm install -g @google/gemini-cli +``` + +**Homebrew (macOS/Linux):** + +```bash +brew install gemini-cli +``` + +Verify installation: + +```bash +gemini --version +``` + +You can also run without installing using `npx @google/gemini-cli`. + +When you launch Gemini CLI inside Warp, Warp auto-detects the agent session and surfaces integrated controls, including rich input, code review, vertical tab metadata, and more. + +## 2. Authenticate + +The first time you run Gemini CLI, it prompts you to choose an authentication method. + +```bash +gemini +``` + +Select **Sign in with Google** and complete the browser authentication flow. Once authenticated, the token is stored locally and you won't need to sign in again. + +For API key authentication (useful for CI/CD or higher rate limits): + +```bash +export GEMINI_API_KEY=YOUR_API_KEY +``` + +For enterprise environments using Vertex AI, the recommended approach is Application Default Credentials (ADC): + +```bash +export GOOGLE_CLOUD_PROJECT=YOUR_PROJECT_ID +export GOOGLE_CLOUD_LOCATION=YOUR_LOCATION +export GOOGLE_GENAI_USE_VERTEXAI=true +gcloud auth application-default login +``` + +See the [Gemini CLI authentication guide](https://geminicli.com/docs/get-started/authentication/) for all Vertex AI auth methods. + +## 3. Start your first session + +Navigate to any project directory and launch Gemini CLI: + +```bash +cd ~/your-project +gemini +``` + +Try giving it a task, for example: + +``` +Explain the architecture of this project +``` + +Or something more hands-on: + +``` +Add error handling to the database connection module +``` + +Gemini CLI reads the relevant files, proposes changes, and asks for confirmation before modifying anything. + +## 4. Configure for your project + +Create a `GEMINI.md` file at your project root to teach Gemini CLI your project's conventions. Gemini CLI reads this file at the start of every session. + +```markdown +# My Project + +## Stack +- Backend: Node.js, Express, TypeScript +- Database: PostgreSQL with Prisma ORM +- Testing: Vitest for unit tests, Playwright for e2e + +## Commands +- `npm run dev` starts the dev server +- `npm test` runs the test suite +- `npm run lint` checks code style + +## Conventions +- Use ESM imports (no require()) +- All API endpoints need Zod input validation +- Run `npm test` before committing +``` + +This prevents Gemini CLI from guessing your conventions and ensures it follows your team's standards from the first prompt. + +## 5. Choose a model + +Gemini CLI defaults to the latest Gemini model. To use a specific model: + +```bash +gemini -m MODEL_NAME +``` + +You can also switch models during a session with the `/model` command. See the [Gemini CLI documentation](https://github.com/google-gemini/gemini-cli) for the current model list. + +:::note +Gemini CLI does not currently support agent notifications in Warp. You won't receive desktop alerts when Gemini CLI needs input, so keep the tab visible or check back periodically during longer tasks. All other Warp agent features (rich input, code review, vertical tabs) work fully. +::: + +## Productivity tips + +* **Use voice to prompt Gemini CLI** — Dictate complex instructions instead of typing them. Warp supports [voice transcription](/agent-platform/local-agents/interacting-with-agents/voice/) that works with any CLI agent, including Gemini CLI. +* **Attach images as context** — Paste screenshots of bugs, designs, or error messages into your prompt. Warp's [images as context](/agent-platform/local-agents/agent-context/images-as-context/) feature lets Gemini CLI see what you see. +* **Review diffs visually** — After Gemini CLI makes changes, open Warp's [Code Review panel](/code/code-review/) (`⌘+Shift++`) to see a visual diff. You can leave inline comments and send them back to Gemini CLI for corrections. +* **Run Gemini CLI alongside other agents** — Use [vertical tabs](/terminal/windows/vertical-tabs/) to run Gemini CLI and Claude Code or Codex side by side on the same task. Compare their approaches and pick the best output. +* **Compose richer prompts** — Press `Ctrl+G` to open Warp's rich input editor for Gemini CLI, giving you a full text editor experience instead of raw CLI input. +* **Use built-in Google Search** — Gemini CLI can ground responses with real-time web search. Ask it to research current best practices or look up documentation while working on your code. + +{/* If a standalone summary feels valuable, add a ## Recap heading above this paragraph. */} + +## Next steps + +You installed Gemini CLI, authenticated with your Google account, started your first session, and configured it for your project. Gemini CLI is now set up as a working coding agent in Warp. + +Explore related guides and features: + +* [Set up Ollama for local models](/guides/external-tools/how-to-set-up-ollama/) to pair Gemini CLI with local model workflows +* [Code Review panel](/code/code-review/) — review and refine agent-generated code +* [Gemini CLI in Warp](https://warp.dev/agents/gemini-cli) — overview of Gemini CLI support in Warp +* [Third-party CLI agents](/agent-platform/cli-agents/overview/) — all supported agents and Warp's universal agent features +* [Gemini CLI documentation](https://github.com/google-gemini/gemini-cli) — Google's official reference diff --git a/src/content/docs/guides/external-tools/how-to-set-up-ollama.mdx b/src/content/docs/guides/external-tools/how-to-set-up-ollama.mdx new file mode 100644 index 0000000..9df5eeb --- /dev/null +++ b/src/content/docs/guides/external-tools/how-to-set-up-ollama.mdx @@ -0,0 +1,83 @@ +--- +title: How To Set Up Ollama +description: >- + Install Ollama, run LLMs locally, compare model performance, and integrate + local models into your apps using Warp. +sidebar: + label: "Set up Ollama" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Running AI models locally just got easier — and faster — with Ollama.\ +\ +In this guide, we’ll walk through how to use Warp to install, profile, and integrate Ollama into your local setup. + +<VideoEmbed url="https://youtu.be/Aq8vDxUg4VE?si=wLyHG7S0NTpC6o7B" /> + +--- + +### 1. Check Your System Specs + +Before running large language models (LLMs) locally, confirm your hardware can handle them. + +Example setups: + +* Mac: 64GB unified memory — good for larger models but with lower throughput. +* Windows (NVIDIA RTX 5090): 32GB VRAM — excellent performance, but limited by VRAM capacity. + +> 🧠 Rule of thumb: You’ll need roughly 1GB of VRAM per billion parameters. + +--- + +### 2. Run Your First Model + +Run a model locally: + +> ollama run gpt-oss + +For example: + +* Try GPT-OSS 20B (requires ≥16GB VRAM, supports tool calling). +* Then try Mistral 8B for a faster, smaller alternative. + +Compare their performance and quality side-by-side.\ +Use Warp to easily monitor GPU usage and model response time. + +--- + +### 3. Understanding Model Terms + +Here’s a quick glossary for choosing the right local model: + +| Term | Meaning | +| ---------------- | ------------------------------------------------------------------ | +| **Thinking** | The model “thinks” before answering; better for complex reasoning. | +| **Tools** | Models can use external utilities (e.g., web search). | +| **Vision** | Can process and respond to images. | +| **Embedding** | Converts text to numeric form for search or RAG pipelines. | +| **Quantization** | Reduces memory use by lowering precision (e.g., 4-bit). | + +--- + +### 4. Integrate Ollama into Your App + +Most apps use OpenAI-compatible APIs, so integration is simple. + +1. Open your app’s code in Warp. +2. Locate the OpenAI client initialization. +3. Replace the base URL with Ollama's +4. Update your API key and model name. + +Warp helps you quickly locate, edit, and test the integration directly from the terminal. + +--- + +### 6. Customize Model Behavior + +Pull and modify a model. + +Then save it as a custom model with new settings like temperature or system prompt. + +Use Warp to generate a model file automatically. + +This adds a structured system prompt for that task — ready to use instantly. diff --git a/src/content/docs/guides/external-tools/how-to-set-up-opencode.mdx b/src/content/docs/guides/external-tools/how-to-set-up-opencode.mdx new file mode 100644 index 0000000..c7ac065 --- /dev/null +++ b/src/content/docs/guides/external-tools/how-to-set-up-opencode.mdx @@ -0,0 +1,138 @@ +--- +title: How to set up OpenCode +description: >- + Set up OpenCode in Warp, configure it for your project, and learn + productivity tips for faster AI-assisted coding workflows. +sidebar: + label: "Set up OpenCode" +--- + +OpenCode is an open-source coding agent that runs in your terminal. It supports 75+ LLM providers, features a built-in terminal UI (TUI), and lets you edit code, execute commands, and manage sessions from natural language prompts. This guide takes you from installation to a working OpenCode session in Warp in about 5 minutes, then shows you how to get the most out of it. + +## Prerequisites + +* **An LLM provider account** — OpenCode connects to any supported provider (Anthropic, OpenAI, Google, and others) via API key, or use OpenCode Zen for a curated model list. See [OpenCode configuration](https://opencode.ai/docs#configure) for details. +* **macOS, Linux, or Windows (via WSL)** — WSL is recommended for the best experience on Windows. See [OpenCode docs](https://opencode.ai/docs) for full platform details. + +## 1. Install OpenCode + +Follow the [official OpenCode installation guide](https://opencode.ai/docs#install) to install OpenCode. The install script is the fastest method: + +```bash +curl -fsSL https://opencode.ai/install | bash +``` + +You can also install via npm or Homebrew: + +```bash +npm install -g opencode-ai +``` + +```bash +brew install anomalyco/tap/opencode +``` + +See the [OpenCode docs](https://opencode.ai/docs#install) for additional installation methods including Homebrew taps, platform-specific binaries, and Docker. + +When you launch OpenCode inside Warp, Warp auto-detects the agent session and surfaces integrated controls, including rich input, code review, vertical tab metadata, and more. + +## 2. Authenticate + +OpenCode supports multiple LLM providers. Run the `/connect` command inside OpenCode's TUI to configure a provider, or set API keys as environment variables: + +```bash +# For Anthropic models +export ANTHROPIC_API_KEY=YOUR_API_KEY + +# For OpenAI models +export OPENAI_API_KEY=YOUR_API_KEY + +# For Google Gemini models +export GEMINI_API_KEY=YOUR_API_KEY +``` + +Outside the TUI, run `opencode auth login` from the command line for interactive provider setup. Credentials are stored locally in `~/.local/share/opencode/auth.json`. + +## 3. Start your first session + +Navigate to any project directory and launch OpenCode: + +```bash +cd ~/your-project +opencode +``` + +OpenCode starts its TUI. Try giving it a task, for example: + +``` +Explain the architecture of this project +``` + +Or something more hands-on: + +``` +Add input validation to the user registration endpoint +``` + +OpenCode reads the relevant files, proposes changes, and asks for confirmation before modifying anything. Use the `Tab` key to switch between Plan mode (read-only suggestions) and Build mode (applies changes). + +## 4. Configure for your project + +Initialize OpenCode for your project by running `/init` inside the TUI. This analyzes your codebase and creates an `AGENTS.md` file at your project root: + +``` +/init +``` + +The `AGENTS.md` file teaches OpenCode your project's structure and conventions. You can also create or edit it manually: + +```markdown +# My Project + +## Stack +- Backend: Python 3.12, FastAPI, SQLAlchemy +- Frontend: React, TypeScript, Vite +- Database: PostgreSQL 16 + +## Commands +- `npm run dev` starts the dev server +- `pytest -v` runs the test suite +- `npm run lint` checks code style + +## Conventions +- Use async/await for all database operations +- Type hints on all function signatures +- ESM imports only (no require()) +``` + +Commit the `AGENTS.md` file to Git so your team shares the same project context. + +## 5. Set up agent notifications + +Warp supports agent notifications for OpenCode through a plugin. If the plugin isn't installed, Warp displays an installation chip in the terminal when you run OpenCode, with setup steps you can follow directly. + +For manual installation and configuration, see [OpenCode in Warp (docs)](/agent-platform/cli-agents/opencode/#setting-up-notifications). + +## Productivity tips + +* **Use voice to prompt OpenCode** — Dictate complex instructions instead of typing them. Warp supports [voice transcription](/agent-platform/local-agents/interacting-with-agents/voice/) that works with any CLI agent, including OpenCode. +* **Attach images as context** — Paste screenshots of bugs, designs, or error messages into your prompt. Warp's [images as context](/agent-platform/local-agents/agent-context/images-as-context/) feature lets OpenCode see what you see. +* **Review diffs visually** — After OpenCode makes changes, open Warp's [Code Review panel](/code/code-review/) (`⌘+Shift++`) to see a visual diff. You can leave inline comments and send them back to OpenCode for corrections. +* **Run OpenCode alongside other agents** — Use [vertical tabs](/terminal/windows/vertical-tabs/) to run OpenCode and Claude Code or Codex side by side on the same task. Compare their approaches and pick the best output. +* **Compose richer prompts** — Press `Ctrl+G` to open Warp's rich input editor for OpenCode, giving you a full text editor experience instead of raw CLI input. + +{/* If a standalone summary feels valuable, add a ## Recap heading above this paragraph. */} + +## Next steps + +You installed OpenCode, authenticated with a provider, started your first session, and configured it for your project. OpenCode is now set up as a working coding agent in Warp. + +Explore related guides and features: + +* [Set up Ollama for local models](/guides/external-tools/how-to-set-up-ollama/) to run OpenCode with local models +* [Code Review panel](/code/code-review/) — review and refine agent-generated code +* [OpenCode in Warp](https://warp.dev/agents/opencode) — overview of OpenCode support in Warp +* [OpenCode in Warp (docs)](/agent-platform/cli-agents/opencode/) — full reference for OpenCode's Warp integration, including notification setup +* [Third-party CLI agents](/agent-platform/cli-agents/overview/) — all supported agents and Warp's universal agent features +* [OpenCode documentation](https://opencode.ai/docs) — official reference +* [opencode-warp plugin](https://github.com/warpdotdev/opencode-warp) — notification plugin source and updates diff --git a/src/content/docs/guides/external-tools/linear-mcp-retrieve-issue-data.mdx b/src/content/docs/guides/external-tools/linear-mcp-retrieve-issue-data.mdx new file mode 100644 index 0000000..fa0e769 --- /dev/null +++ b/src/content/docs/guides/external-tools/linear-mcp-retrieve-issue-data.mdx @@ -0,0 +1,64 @@ +--- +title: "Linear MCP: Retrieve issue data" +description: >- + Add the Linear MCP server to Warp and query your issues, tasks, and + assignments directly from the terminal. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Learn how to connect the Linear MCP server in Warp so your AI agent can access live data — like issues, tickets, and user assignments — directly from your Linear workspace. + +<VideoEmbed url="https://youtu.be/jxeMfuS1pXk" /> + +--- + +#### Overview + +This tutorial covers how to: + +* Add and configure a Linear MCP server in Warp +* Use MCP to query and retrieve issue data + +### 1. Adding the Linear MCP Serve + +#### Add a new server in Warp + +* In Warp, open Warp Drive → Personal → MCP Servers.\ + Alternatively, press `⌘P` and type **MCP servers** to open the palette. +* Click **Add New Server**. +* Paste in this JSON + +```json +{ + "linear": { + "command": "npx", + "args": ["-y", "mcp-remote", "https://mcp.linear.app/sse"], + "env": {}, + "working_directory": null + } +} +``` + +* Click Save. +* Warp will immediately start the server. +* You should now see Linear MCP listed as Running. + +--- + +### 2. Testing the Connection + +After saving, retry your earlier query: + +``` +Show me all Linear tasks assigned to me. +``` + +Warp’s agent will now call the Linear MCP server to fetch your data. You can click inside the response panel to inspect the **raw API response** — ideal for debugging or understanding what’s being fetched. + +If the server can’t find your user, it may be due to your Linear login address. Try querying a teammate to confirm the connection: + +``` +Show tasks assigned to [teammate name]. +``` + +Once verified, the agent can display a full list of tasks. diff --git a/src/content/docs/guides/external-tools/linear-mcp-updating-tickets-with-a-lean-build-approach.mdx b/src/content/docs/guides/external-tools/linear-mcp-updating-tickets-with-a-lean-build-approach.mdx new file mode 100644 index 0000000..5387984 --- /dev/null +++ b/src/content/docs/guides/external-tools/linear-mcp-updating-tickets-with-a-lean-build-approach.mdx @@ -0,0 +1,80 @@ +--- +title: "Linear MCP: Updating Tickets with a Lean Build Approach" +description: >- + Use Warp's Linear MCP integration to update ticket descriptions, propagate + changes to subtasks, and maintain a lean build strategy. +sidebar: + label: "Linear MCP: Update tickets with a lean build approach" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +Learn how to use Warp’s Linear MCP integration to update tickets programmatically while maintaining a lean build strategy. + +<VideoEmbed url="https://www.youtube.com/watch?v=hqleW6jDCbY" /> + +--- + +## Overview + +This walkthrough demonstrates: + +* Updating Linear tickets via Warp’s MCP integration +* Structuring tasks around a lean development stack +* Observing real-time synchronization of ticket data +* Testing agent autonomy when editing related subtasks + +<Steps> + +1. #### Setting Up the Scenario + + The goal is to use Warp’s agent to update a Linear epic with a new, leaner build approach and reflect the changes in related subtasks. + + First, open your Linear project and locate the target epic.\ + Copy the **ticket ID** (e.g. “Empty Studio 36”). + +2. #### Define the Update Prompt + + Within Warp, run the MCP command to edit the Linear issue. + + **Prompt** + + ``` + Use the warp-server-staging gcloud project and pull logs for the last 10 minutes from the warp-server Cloud Run instance. + Organize them by info, warning, and error levels. + Create a histogram across message types, and highlight the most concerning errors to investigate. + ``` + Warp parses the issue context and updates the ticket’s fields accordingly. + +3. #### Observing the Changes + + After execution: + + * The Linear ticket reflects the new **Next.js + Supabase** stack. + * Tasks like _Build Foundation_, _Implement AI-powered PRD Generation_, and _Set up Development Environment_ are updated. + * Time estimates automatically adjust from _4–6 weeks_ to _2–3 weeks_. + * Complex integrations (AI and Linear App) are deferred to a future phase. + +4. #### Propagating Updates to Child Tasks + + Warp’s agent can cascade changes to linked subtasks.\ + If it begins editing other epics unexpectedly, you can constrain its scope by specifying task IDs in the prompt: + + ``` + Only update the ticket with ID <ticket_number>. + Do not modify other epics or related tickets. + ``` + +5. #### Review and Verification + + Re-open the Linear epic to confirm updates: + + * **Frontend specs** reflect the lean stack. + * **Child tasks** align with phase 1 deliverables. + * **Deferred features** (e.g., advanced integrations) are pushed to phase 2. + + :::note + This demonstrates Warp’s ability to _maintain and modify tickets intelligently_, not just create them. + ::: + +</Steps> diff --git a/src/content/docs/guides/external-tools/puppeteer-mcp-scraping-amazon-web-reviews.mdx b/src/content/docs/guides/external-tools/puppeteer-mcp-scraping-amazon-web-reviews.mdx new file mode 100644 index 0000000..ac50f50 --- /dev/null +++ b/src/content/docs/guides/external-tools/puppeteer-mcp-scraping-amazon-web-reviews.mdx @@ -0,0 +1,125 @@ +--- +title: "Puppeteer MCP: Scraping Amazon Web Reviews" +description: >- + Configure the Puppeteer MCP server in Warp to automate browser tasks like + navigating sites, scraping product data, and analyzing reviews. +sidebar: + label: "Puppeteer MCP: Scrape Amazon web reviews" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +:::note +This tutorial demonstrates how to configure and use the **Puppeteer MCP server** inside Warp to scrape Amazon web reviews. +::: + +<VideoEmbed url="https://youtu.be/rrxfS9u1XRA?si=Bzaxm6Qb00okv03t&t=134" /> + +--- + +### 🧠 Overview + +**Puppeteer MCP** integrates Warp’s agents with the browser, letting you automate tasks such as navigation, form filling, screenshotting, and scraping content.\ +\ +Once configured, Warp can issue Puppeteer commands directly from prompts, enabling full **browser automation** without manual scripting. + +You’ll learn how to: + +* Set up the Puppeteer MCP server. +* Use Warp’s voice input and AI to describe automation tasks. +* Execute browser workflows hands-free. +* Capture, scrape, and analyze web data programmatically. + +--- + +<Steps> + +1. #### Configure the Puppeteer MCP Server + + Open the MCP panel in Warp: + + * Press **Cmd + Shift + P** (Mac) or **Ctrl + Shift + P** (Windows/Linux) to open the **Command Palette**. + * Search for `MCP` and open the **MCP Panel**. + + Add the Puppeteer MCP config: + + * Click **Add**, then paste in the provided JSON configuration for Puppeteer: + + ```json + { + "puppeteer": { + "command": "npx", + "args": [ + "-y", + "@modelcontextprotocol/server-puppeteer" + ], + "env": {}, + "working_directory": null + } + } + ``` + Save your configuration. Available endpoints will include: + + * `puppeteer.navigate` + * `puppeteer.fill` + * `puppeteer.screenshot` + * `puppeteer.evaluate` + + These represent actions Warp can call automatically through its AI agent. + +2. #### Use Voice Input to Trigger Automation + + Enable **voice input** by clicking the microphone icon in Warp. Then speak your automation prompt naturally. + + ``` + Can you go to Amazon search for "white t-short women?" + + Scrape the results so the titles, prices, and links are extracted. + Then open each product link and summarize the product reviews. + Finally, give me a recommendation for which shirt to buy based on the combination of the pricing and review quality. + ``` + + #### Watch Puppeteer Automate the Workflow + + Behind the scenes, Puppeteer: + + * Navigates to Amazon. + * Fills the search bar with “white t-shirt woman.” + * Scrapes the product results — capturing titles, prices, and product links. + * Clicks into each product and extracts review data using JavaScript selectors. + * Takes screenshots of the pages for reference. + + You can see the browser (Amazon) and Warp side-by-side as Puppeteer performs these steps autonomously. + + :::note + Puppeteer runs fully headless or in visible browser mode — you don’t need to touch your mouse or keyboard. + ::: + + #### Analyze and Summarize Results + + Once the scrape is complete, Warp compiles the data and provides a ranked list of products. Example output (from transcript): + + | Product | Price | Rating | Summary | + | ---------------- | ----- | ------ | --------------------- | + | Cozy T-Shirt | $8 | ⭐ 4.5 | Soft fabric, good fit | + | Comfy Cotton Tee | $10 | ⭐ 4.2 | Slightly looser fit | + | Basic White Top | $6 | ⭐ 3.8 | Mixed quality reviews | + + Warp’s recommendation: + + > “The Cozy T‑Shirt — $8, 4.5 stars, good fit, and soft fabric.” + + #### Apply Puppeteer MCP to Other Scenarios + + The same setup works for: + + * Product research – Compare reviews or specs across multiple sites. + * Competitive analysis – Scrape competitors’ pricing or product data. + * Web testing – Automate user flows like login or checkout. + * Repetitive data tasks – Periodic scraping or screenshot capture. + + :::tip + Puppeteer MCP lets Warp act like your hands in the browser — navigating, scraping, and summarizing data while you focus on analysis. + ::: + +</Steps> diff --git a/src/content/docs/guides/external-tools/sentry-mcp-fix-sentry-error-in-empower-website.mdx b/src/content/docs/guides/external-tools/sentry-mcp-fix-sentry-error-in-empower-website.mdx new file mode 100644 index 0000000..28780ec --- /dev/null +++ b/src/content/docs/guides/external-tools/sentry-mcp-fix-sentry-error-in-empower-website.mdx @@ -0,0 +1,118 @@ +--- +title: "Sentry MCP: Fix Sentry Error in Empower Website" +description: >- + Connect the Sentry MCP server to Warp, fetch live error data, diagnose stack + traces, and auto-generate fixes for production issues. +sidebar: + label: "Sentry MCP: Fix Sentry error in Empower website" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +:::note +This tutorial is based solely on the provided transcript. It teaches how to use the **Sentry MCP Server** within Warp to fetch live error data from Sentry, analyze stack traces, and automatically generate fixes for issues in your codebase. +::: + +<VideoEmbed url="https://youtu.be/rrxfS9u1XRA?si=fVUfjQJSOlyLFBJT" /> + +### Overview + +The **Sentry MCP server** gives Warp’s AI agents access to authenticated Sentry error data.\ +This enables detailed diagnostics and automated fixes that would otherwise be impossible using AI alone. + +You’ll learn how to: + +* Connect the Sentry MCP server inside Warp. +* Trigger live error retrieval from Sentry. +* Diagnose code issues and generate patches automatically. +* Integrate Sentry debugging into your daily development loop. + +<Steps> + +1. #### Set Up the Sentry MCP Server + + Open the MCP panel in Warp: + + * Mac: Cmd + Shift + P + * Windows/Linux: Ctrl + Shift + P\ + Search for “MCP” and select the **MCP Panel**. + + Click **Add**, then paste your configuration: + + ```json + { + "sentry": { + "command": "npx", + "args": [ + "-y", + "mcp-remote@latest", + "https://mcp.sentry.dev/mcp" + ], + "env": {}, + "working_directory": null + } + } + ``` + Save the configuration and ensure it appears in the MCP panel. + +2. #### Run Your App and Trigger an Error + + We're using the [**Empower Plant** repository](https://github.com/sentry-demos/empower) — Sentry’s official demo project. This fake e-commerce app includes a React frontend and multiple backends, each containing intentional bugs for testing. + + Run the app locally: + + ```bash + npm install + npm start + ``` + + Open the site in your browser and trigger a few known errors. + +3. #### Capture the Error in Sentry + + 1. Go to your **Sentry Dashboard**. + 2. Locate the triggered issue (for example, a `TypeError`). + 3. Copy the issue’s URL from the Sentry interface. + + Example: + + ``` + https://sentry.io/organizations/demo/issues/12345/ + ``` + +4. #### Diagnose the Error Using Warp + + Back in Warp, prompt the AI agent to fetch and analyze the issue: + + ``` + Diagnose this Sentry error and show where it’s coming from in my code. + Create a fix. + ``` + + The Sentry MCP calls `getIssueDetails`, fetching the stack trace and error metadata directly from Sentry. Warp then scans your local codebase, cross-references the error location, and identifies the root cause. + + From this example: + + > The issue was caused by calling `.toUpperCase()` on an array instead of a string. + + Warp’s agent automatically writes a fix — changing the code to handle the array properly. + +5. #### Apply the Generated Fix + + Warp produces a suggested code change inline. Review the diff and apply it automatically with one click. + +6. #### Integrate Into Your Workflow + + Use Sentry MCP whenever you encounter production or staging errors. Warp can pull the latest issues, analyze them, and suggest patches. + + Ideal for: + + * Debugging live production errors. + * Triaging complex stack traces. + * Creating immediate hot-fixes without switching tools. + + :::tip + With Sentry MCP, Warp becomes a live debugging console — connecting your code editor, terminal, and Sentry into a single intelligent feedback loop. + ::: + +</Steps> diff --git a/src/content/docs/guides/external-tools/sqlite-and-stripe-mcp-basic-queries-you-can-make-after-set-up.mdx b/src/content/docs/guides/external-tools/sqlite-and-stripe-mcp-basic-queries-you-can-make-after-set-up.mdx new file mode 100644 index 0000000..aec41f8 --- /dev/null +++ b/src/content/docs/guides/external-tools/sqlite-and-stripe-mcp-basic-queries-you-can-make-after-set-up.mdx @@ -0,0 +1,96 @@ +--- +title: "SQLite and Stripe MCP: Basic Queries You Can Make After Set Up" +description: >- + Connect SQLite and Stripe MCP servers to Warp and run conversational queries + against your local database and payment data. +sidebar: + label: "SQLite and Stripe MCP: Basic queries you can make after setup" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +This tutorial teaches you how to use **MCP servers** to connect Warp to **Stripe** and **SQLite**, showing how AI transforms the command line into a connected, conversational workspace. + +<VideoEmbed url="https://x.com/svpino/status/1937896922297311390" /> + +<Steps> + +1. #### Enabling MCP in Warp + + Warp now supports configuring any MCP server directly from the terminal. + + To set it up: + + * Open **Settings → AI → MCP Servers** in Warp. + * Click **Add Server**, and choose from a list of available MCP configurations. + * Once added, Warp automatically connects and authorizes the agent to use those tools. + + In this demo, two MCP servers were enabled: + + * **SQLite Server** – for running local database queries + * **Stripe Server** – for retrieving and analyzing payment data + +2. #### Querying Stripe + + Once configured, you can issue conversational prompts to the terminal — no manual API calls required. + + Example — Querying Stripe + + ``` + How many customers do I have in Stripe? + ``` + + Warp connects to the Stripe MCP server, confirms the action, and returns: + + > “You have 3 customers.” + + You can continue naturally: + + ``` + List the payments made by the first customer. + ``` + + The agent retrieves seven payment intents — one successful, six canceled — all live from your Stripe test account. + + Note: MCP’s confirmation prompts can be disabled once you trust a given server or agent. + +3. #### Querying SQLite + + The same workflow applies to databases. + + Example — Querying SQLite + + ``` + What SQL tables do I have access to? + ``` + + Warp lists all available tables from the local SQLite database. + + ``` + Break down female penguins by island. + ``` + + Warp translates this into a structured SQL query and executes it, returning: + + > “Bisco Island — 51 female penguins; Dream Island — ...” + + Follow-up prompts work contextually: + + ``` + Do the same with male penguins. + ``` + + Warp runs the updated SQL query and displays results inline. + +4. #### Why This Matters + + This demo highlights how Warp’s AI and MCP support combine to make your terminal: + + * **Connected** — Access cloud APIs, local data, or enterprise tools instantly. + * **Conversational** — Run natural language prompts for structured data retrieval. + +5. :::note + “Even two years ago, no one could’ve imagined a terminal capable of this. Warp has officially redefined what a terminal can be.” — Santiago + ::: + +</Steps> diff --git a/src/content/docs/guides/external-tools/using-mcp-servers-with-warp.mdx b/src/content/docs/guides/external-tools/using-mcp-servers-with-warp.mdx new file mode 100644 index 0000000..183ad82 --- /dev/null +++ b/src/content/docs/guides/external-tools/using-mcp-servers-with-warp.mdx @@ -0,0 +1,92 @@ +--- +title: Using MCP Servers with Warp +description: >- + Connect MCP servers to Warp's agent, add Rules for automatic tool selection, + and resolve tickets using external systems like Linear. +sidebar: + label: "Connect Agents to MCP servers" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +<VideoEmbed url="https://www.youtube.com/watch?v=8vn2brhJrF8" /> + +### 1. What Are MCP Servers? + +MCP (Model Context Protocol) servers let Warp agents connect to external systems like GitHub, Linear, or Jira — so they can read, write, and reason about those systems natively. + +Each MCP server adds its own “tools” to Warp’s agent.\ +For example: + +* The Linear MCP Server handles tickets. +* The GitHub MCP Server handles pull requests and issues. + +--- + +### 2. Problem Setup + +Andrew starts with Warp’s universal input, but it doesn’t yet know what a “ticket” is. + +> Prompt Example:\ +> “Help me solve this ticket.” + +At this point, Warp can’t find or interpret the ticket, because no MCP server is connected. + +--- + +### 3. Adding the Linear MCP Server + +To connect Linear: + +1. Open the **MCP Panel** in Warp +2. Click **Add Server** +3. Paste in the JSON configuration for the Linear MCP Server + +Once added, Warp: + +* Starts the MCP server +* Loads its tools (e.g., `get_ticket`, `update_ticket`, `create_ticket`) +* Makes them available to the agent instantly + +--- + +### 4. Using Rules with MCP Servers + +Andrew adds a rule called **check-linear**, which helps the agent automatically associate “tickets” with the Linear MCP Server. + +> **Rule Example:**\ +> “When the user says ‘ticket,’ check Linear.” + +Rules make context switching between systems seamless — the agent doesn’t need reminders. + +--- + +### 5. Dynamic Context Loading + +Warp’s MCP support is **dynamic**: + +* You can start a conversation without any connected MCPs +* Add one mid-session +* The agent automatically updates its context on the next message + +No need to restart Warp or reset your session. + +--- + +### 6. Running the Task + +After adding Linear, Andrew runs: + +> “Help me solve this ticket.” + +Now the agent: + +* Queries Linear for the ticket +* Pulls all related context +* Reads the codebase for linked references +* Generates the appropriate fix + +He verifies the output by running: + +```bash +cargo run +``` diff --git a/src/content/docs/guides/frontend/how-to-actually-code-ui-that-matches-your-mockup-react-tailwind.mdx b/src/content/docs/guides/frontend/how-to-actually-code-ui-that-matches-your-mockup-react-tailwind.mdx new file mode 100644 index 0000000..4b59926 --- /dev/null +++ b/src/content/docs/guides/frontend/how-to-actually-code-ui-that-matches-your-mockup-react-tailwind.mdx @@ -0,0 +1,114 @@ +--- +title: "How To: Actually Code UI That Matches Your Mockup (React + Tailwind)" +description: >- + Prompt Warp to generate pixel-perfect React + Tailwind code from design + mockups, with structured specs and iterative refinement. +sidebar: + label: "Actually code UI that matches your mockup" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +Learn how to prompt Warp’s AI to produce accurate, design-faithful UI code using your preferred framework. + +<VideoEmbed url="https://youtu.be/GA0OO_1o8LA?si=2BLIDNjL5Tr0Nixz" /> + +--- + +## Intro + +This tutorial walks you through generating pixel-perfect front-end code using Warp.\ +\ +By treating the AI like a **UI engineer**, you can get closer to real implementation fidelity — especially when working from design mockups. + +Although this example uses **React** and **Tailwind**, the same method applies to **Vue**, **Next.js**, or **Svelte**. + +--- + +<Steps> + +1. #### The Problem + + When designing UI with AI, your intended design often gets lost in translation.\ + AI struggles with visual fidelity — but structured prompts can help fix that. + +2. #### The Prompt + + Step — Generate full specifications: + + ``` + Analyze this web design mockup as a senior UI engineer would. Create a complete technical specification: + + 1. DESIGN SYSTEM TOKENS: + - Extract the color palette with semantic naming (primary, secondary, surface, text) + - Identify the type scale (heading levels, body text sizes) + - Document the spacing scale pattern (4px, 8px, 16px, etc.) + - List border radius values used consistently + + 2. LAYOUT ARCHITECTURE: + - Describe the overall page structure using semantic HTML5 elements + - Identify CSS Grid vs Flexbox usage for each section + + 3. COMPONENT SPECIFICATIONS: + For each unique component, provide: + - Semantic HTML structure + - CSS layout method + - All visual states (default, hover, focus, active, disabled) + - Exact dimensions and spacing + - Animation/transition properties + + 4. RESPONSIVE BEHAVIOR: + - Describe how the layout adapts (even if only desktop is shown) + - Note which elements stack, hide, or resize + - Identify touch targets that need enlarging on mobile + + 5. ACCESSIBILITY REQUIREMENTS: + - Color contrast ratios for text/background combinations + - Interactive element sizes (minimum 44x44px touch targets) + - Focus indicator styles + - Screen reader considerations for decorative elements + + Format as a structured spec that includes both the visual description AND implementation notes. Flag any ambiguous design decisions that need clarification. + + ``` + + Next, give Warp the right prompt to start the code implementation: + + ``` + Using this design specification, build a responsive React component with Tailwind CSS: + + Requirements: + - Create reusable components for each element in the spec + - Use CSS variables for the design tokens + - Implement all interactive states + - Ensure mobile-first responsive design + - Add proper semantic HTML and ARIA labels + - Include Framer Motion for any animations mentioned + - Match the spacing system exactly using Tailwind's spacing scale + + Create a pixel-perfect implementation that matches the original design. + + ``` + +3. #### Validate and Iterate + + Warp outputs component files and layout structure.\ + You can review spacing, font weights, and responsive behavior directly in preview. + + If details feel off, prompt again with clarifications like: + + ``` + Tighten vertical spacing between header and subtext. + ``` + +4. #### Recap + + You’ve learned how to: + + * Prompt AI for structured UI specs + * Generate React + Tailwind implementations + * Iterate visually for design parity + + > Treating the AI like a teammate — not a tool — yields interfaces that finally match your vision. + +</Steps> diff --git a/src/content/docs/guides/frontend/how-to-replace-a-ui-element-in-warp-rust-codebase.mdx b/src/content/docs/guides/frontend/how-to-replace-a-ui-element-in-warp-rust-codebase.mdx new file mode 100644 index 0000000..f145511 --- /dev/null +++ b/src/content/docs/guides/frontend/how-to-replace-a-ui-element-in-warp-rust-codebase.mdx @@ -0,0 +1,97 @@ +--- +title: "How To: Replace A UI Element in Warp (Rust Codebase)" +description: >- + Use Agent Mode in Warp to plan and execute icon replacements across a large + Rust codebase — with live diffs, auto-compilation, and self-correction. +sidebar: + label: "Replace a UI element in Warp" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; +import { Steps } from '@astrojs/starlight/components'; + +Learn how to use Warp’s AI coding features to make live code changes — in this example, replacing an icon throughout Warp’s massive Rust codebase using an agentic workflow. + +<VideoEmbed url="https://youtu.be/V2pwBN6Vt7k" /> + +:::note +This demo showcases Warp’s ability to safely make intelligent code changes within a multi-million-line codebase by providing structured prompts, reviewing diffs in real time, and letting the agent compile and self-correct. +::: + +<Steps> + +1. #### Define the Task + + The goal here is to replace all instances of the **sparkle icon** with the new **agent icon**, especially within the history menu. + + Open your project in Warp and start by prompting the agent directly (either by typing or speaking): + + ``` + Please create a new branch for me according to the format in the attached Linear URL. + + I’ve attached screenshots of what the agent mode and sparkle icons look like. + I would like you to understand those icons, search for their use in the code, + and wherever we’re using sparkles, replace them with the agent mode icon. + Specifically, make sure this happens in the history menu. + Please give me a plan before making any coding changes. + ``` + + Attach any relevant Linear issue links or screenshots to help the agent identify assets accurately. + +2. #### Review the Plan + + Warp’s agent parses your request and generates a plan for code edits.\ + It identifies files and functions where the sparkle icon is used. + + If the plan looks correct, approve it to proceed. + + Follow-up prompt example: + + ``` + Yes, proceed — and please rename the function from renderAISparklesIcon + to something like renderAgentModeIcon. + ``` + + Warp automatically updates function names, asset references, and component usage. + +3. #### View AI Diffs in Real Time + + Warp lets you view live diffs as the agent edits your files. + + * Diffs show changes to both render logic and function naming. + * You can choose to auto-accept or manually review diffs. + * These settings can be adjusted under AI Settings → Apply Changes Automatically. + + :::note + Note: The demo runs with “auto-accept” enabled, allowing Warp to apply diffs as soon as they’re validated. + ::: + +4. #### Compilation and Fixes + + After editing, Warp’s agent runs: + + ```bash + cargo check + ``` + + to verify compilation. + + If compilation fails (e.g., missing imports), the agent automatically corrects and retries — mimicking a human debugging process. + +5. #### Testing the Change + + Once compiled: + + * Run your project locally to confirm visual changes. + * Check that the agent icon now replaces the sparkle icon in all targeted locations. + +6. #### Recap + + Warp’s agent completed the full flow: + + 1. Understood a Linear ticket and visual context + 2. Created a new branch + 3. Planned and executed the icon replacement + 4. Auto-fixed compile issues + 5. Verified the final result in-app + +</Steps> diff --git a/src/content/docs/guides/getting-started/10-coding-features-you-should-know.mdx b/src/content/docs/guides/getting-started/10-coding-features-you-should-know.mdx new file mode 100644 index 0000000..ae95af7 --- /dev/null +++ b/src/content/docs/guides/getting-started/10-coding-features-you-should-know.mdx @@ -0,0 +1,125 @@ +--- +title: 10 Coding Features You Should Know +description: >- + Discover 10 essential coding features in Warp — file search, tabbed editor, + find and replace, syntax highlighting, code review panel, and more. +sidebar: + label: "10 coding features you should know" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +## 10 Coding Features You Should Know in Warp + +If you didn’t already know, you can code directly in Warp. + +Warp includes a full set of features that make editing, reviewing, and navigating your codebase far easier than in a traditional dev tool. + +<VideoEmbed url="https://youtu.be/oeonZ-jtzhA?si=yNXPBeFk5SV8oGHw" /> + +\ +Let’s walk through the 10 core features you need to know to get started. + +--- + +### 1. Search for Files + +Open the **Command Palette**: + +* **Mac:** `Cmd + P` +* **Windows/Linux:** `Ctrl + Shift + P` + +Then press: + +* **Mac:** `Cmd + O` +* **Windows/Linux:** `Ctrl + O` + +From here, you can search and open any file in your project — no need to `cd` around or remember long paths. + +--- + +### 2. Tabbed File Viewer + +When you open files, Warp shows them in **tabs** rather than split panes.\ +This keeps your workspace clean while still allowing you to switch quickly between multiple files. + +--- + +### 3. Full Editor Support + +You can edit code directly inside Warp — just like any modern editor. + +No need for memorized shortcuts: + +* Click and type normally +* Highlight, copy, paste, or undo using familiar shortcuts + +--- + +### 4. Find and Replace + +Warp supports full **find and replace** with: + +* Regular expressions +* Multi-cursor editing +* Replace-all +* Preserve-case rules + +These features make renaming variables or refactoring code fast and consistent. + +--- + +### 5. Syntax Highlighting + +Warp supports syntax highlighting for **dozens of languages and frameworks**.\ +It appears both in: + +* Agent-generated diffs +* The file editor view + +This makes it easy to visually scan code at a glance. + +--- + +### 6. Linked File References + +When Warp’s agent references a file, it automatically **links to the exact line of code**.\ +Clicking the link opens that file at that line inside Warp — perfect for tracing logic or verifying changes. + +> ⚙️ **Tip:** In **Settings → Features**, set Warp as your default editor for these file links so they open directly in Warp. + +--- + +### 7. Code Review Panel + +Warp provides a **dedicated review panel** summarizing all files and diffs touched by an agent.\ +You can: + +* Review and approve changes +* Edit them inline +* Reference diffs in your next prompt + +This reduces hallucinations and keeps agents grounded in your actual code. + +--- + +### 8. Code Snippet References + +When Warp explains something about your codebase, it surfaces the **exact code snippet**.\ +You can attach that snippet as fresh context for your next prompt. This keeps token usage lean and the agent's focus sharp. + +--- + +### 9. Codebase Indexing + +Warp can automatically **index your repositories** for faster, more context-aware responses.\ +This makes it easier for agents to: + +* Summarize large codebases +* Fix bugs +* Handle refactors intelligently + +--- + +### 10. File Tree View + +Click the file-tree icon in Warp to **browse your entire repo** and open any file with a single click. diff --git a/src/content/docs/guides/getting-started/how-to-customize-warps-appearance.mdx b/src/content/docs/guides/getting-started/how-to-customize-warps-appearance.mdx new file mode 100644 index 0000000..0b9799f --- /dev/null +++ b/src/content/docs/guides/getting-started/how-to-customize-warps-appearance.mdx @@ -0,0 +1,89 @@ +--- +title: "How to: Customize Warp's Appearance" +description: >- + Customize Warp's themes, input placement, AI settings, codebase indexing, + team collaboration, and visual appearance to fit your workflow. +sidebar: + label: "Customize Warp's appearance" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +<VideoEmbed url="https://youtu.be/fzb1JcZ0fFA?si=nkWhujJKAezGfB9k" /> + +Warp is highly customizable — from appearance and keyboard shortcuts to agent behavior and autonomy.\ +\ +Here’s a quick walkthrough of how to make Warp feel like _your_ development environment. + +--- + +### 1. Changing Themes + +Open the **Command Palette** with: + +* `Cmd + P` (Mac) +* `Ctrl + Shift + P` (Windows/Linux) + +Type **“themes”** to open the theme picker. + +You can preview and apply any theme instantly — for example, switching from the default theme to _Phenomenon_. + +--- + +### 2. Adjusting Input Placement + +Warp’s **input bar** can live in three different positions: + +1. **Bottom-pinned** — chat-style; commands flow upward. +2. **Scrolling input** — traditional terminal style; input stays near the bottom as output moves up. +3. **Top-pinned** _(Warp-exclusive)_ — input stays fixed at the top; results appear below. + +--- + +### 3. Managing AI & Agent Settings + +Open **Settings → AI** to control: + +* Which **model** Warp uses (e.g., Claude 3.5 for code generation, GPT-4o for planning). +* How much **autonomy** agents have for: + * Reading files + * Generating diffs + * Running commands + * Planning tasks + +You can also whitelist or block specific commands that always require confirmation. + +--- + +### 4. Indexing Your Codebases + +Warp prompts you to index your codebase the first time you `cd` into it.\ +Indexing enables faster: + +* Code navigation +* Summaries and searches +* Refactors and bug fixes + +You can also manually re-index a folder from the sidebar anytime. + +--- + +### 5. Team Collaboration + +In the Teams tab, you can: + +* Invite teammates +* Share Warp Drive assets like prompts, templates, and environment variables + +This makes Warp a shared, contextual workspace — not just an individual tool. + +--- + +### 6. Look & Feel + +Under Appearance, you can tweak: + +* Fonts +* App icons +* Padding and editor density +* VIM mode for command editing +* Custom key bindings diff --git a/src/content/docs/guides/getting-started/how-to-make-warps-ui-more-minimal.mdx b/src/content/docs/guides/getting-started/how-to-make-warps-ui-more-minimal.mdx new file mode 100644 index 0000000..3189041 --- /dev/null +++ b/src/content/docs/guides/getting-started/how-to-make-warps-ui-more-minimal.mdx @@ -0,0 +1,86 @@ +--- +title: How to Make Warp’s UI More Minimal +description: >- + Reduce visual noise in Warp by disabling UI elements, switching to a minimal + theme, using the classic prompt, and hiding the tab bar. +sidebar: + label: "Make Warp's UI more minimal" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +<VideoEmbed url="https://www.youtube.com/watch?v=1GKsIT8FSsE" /> + +### 1. Start with the Command Palette + +Open the Command Palette: + +* Mac: `Cmd + P` +* Windows/Linux: `Ctrl + Shift + P` + +From here, type “Disable” to see a full list of UI toggles.\ +Warp will surface options that let you quickly hide features and visual elements. + +--- + +### 2. Key UI Toggles to Disable + +#### Inline & AI Features + +* Disable Auto Suggestions → removes inline code hints. +* Disable Active AI → hides the ghost prompt that suggests agent queries. +* Disable Completion Menu → prevents popup completions from appearing. +* Disable Voice Input → hides the microphone icon. + +#### Interface & Layout + +* Disable Block Dividers → removes the horizontal lines between commands. +* Disable Tab Indicators → hides the colored status markers across your tab bar. +* Disable Dimming Inactive Panes → keeps all split panes at equal brightness. +* Disable VIM Status Bar → removes the VIM indicator if you’re not using VIM mode. + +--- + +### 3. Choose a Simpler Theme + +Visual noise can come from colors too.\ +Try switching to a calmer theme from the Command Palette: + +1. Open the palette again (`Cmd + P`) +2. Type “Theme” +3. Pick one with softer tones — for example: + * Adeberry → calm, gray, minimal aesthetic + * Classic Dark → familiar and focused + +A consistent neutral palette makes Warp feel lighter and easier on the eyes. + +--- + +### 4. Switch to the Classic Prompt + +Warp’s Universal Prompt is great for AI workflows — it supports: + +* Slash commands +* Voice input +* Image context +* Agent Mode + +But if you just want a terminal that behaves like a classic shell, switch to the Classic Prompt: + +1. Open the Command Palette → search “Prompt” +2. Choose Classic Prompt +3. (Optional) Open the Prompt Customizer to toggle chips: + * Keep only what you need (e.g., file path) + * Hide everything else (branch name, context icons, etc.) + +This instantly gives Warp a retro, text-first look — no clutter, no distractions. + +--- + +### 5. Reduce Tab Bar Visibility + +You can make the tab bar appear only when you hover: + +* Open the Settings → Appearance +* Enable “Show Tabs on Hover” + +This keeps your workspace focused while still letting you access tabs when needed. diff --git a/src/content/docs/guides/getting-started/how-to-master-warps-code-review-panel.mdx b/src/content/docs/guides/getting-started/how-to-master-warps-code-review-panel.mdx new file mode 100644 index 0000000..04643fb --- /dev/null +++ b/src/content/docs/guides/getting-started/how-to-master-warps-code-review-panel.mdx @@ -0,0 +1,75 @@ +--- +title: How To Master Warp's Code Review Panel +description: >- + Use Warp's Code Review Panel to view file diffs, edit code inline, + componentize changes, and commit directly — all without leaving the + terminal. +sidebar: + label: "Master Warp's Code Review panel" +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +<VideoEmbed url="https://www.youtube.com/watch?t=47s&v=4JlN0rvoZA8" /> + +### 1. Why Use the Code Review Panel + +Warp’s Code Review Panel helps you stay focused while coding by showing all active file diffs, additions, and deletions — without leaving your workspace. + +--- + +### 2. Start with a Coding Task + +The app has a UI issue: the hover text is black on dark gray, making it unreadable. + +Warp’s agent generates diffs with proposed fixes — but for larger projects, scrolling through them is inefficient. + +--- + +### 3. Opening the Code Review Panel + +Click: + +* View Changes (top-left), or +* The Dirty Chip in your input bar + +This opens the Code Review Panel — available only when inside a Git repo. + +The panel shows: + +* Changed files +* Lines added/deleted +* File-by-file diff summaries + +--- + +### 4. Editing and Reviewing Code + +You can open any file directly from the panel in Warp’s **built-in editor**: + +* Syntax highlighting +* Find & replace +* Inline editing + +Save changes — and they’ll reflect instantly in the diff view. + +--- + +### 5. Componentizing Changes + +Want that same hover fix across the app?\ +Prompt Warp to componentize the hover style. + +Attach the recent diff as context so Warp can generalize it.\ +The agent then creates a `Tooltip` component that reuses your schema everywhere. + +--- + +### 6. Reviewing and Committing + +Once the fix looks correct: + +* Review in the code panel +* Commit directly from Warp +* Watch the panel reset to its “no changes” state + +You can also click to compare your branch against `main` instantly. diff --git a/src/content/docs/guides/getting-started/welcome-to-warp.mdx b/src/content/docs/guides/getting-started/welcome-to-warp.mdx new file mode 100644 index 0000000..a7a2ba4 --- /dev/null +++ b/src/content/docs/guides/getting-started/welcome-to-warp.mdx @@ -0,0 +1,54 @@ +--- +title: Welcome to Warp +description: >- + Get oriented with Warp's agentic terminal. Learn the basics of prompt-based + coding, blending terminal and agent workflows, and navigating the interface. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +<VideoEmbed url="https://www.youtube.com/watch?v=O5E6ze3vqeo" /> + +### 1. Welcome to Warp + +When you open Warp, you’ll see something familiar — a command line interface — but it’s much more than a traditional terminal.\ +\ +Warp is an Agentic Development Environment (ADE), meaning it’s a space where your primary mode of interaction is through prompts to an AI agent. + +You can still use Warp just like any terminal: + +```bash +ls +pwd +``` + +Warp executes those commands exactly as you’d expect.\ +\ +But when you type natural language — like _“describe my open git changes”_ — Warp interprets it as a prompt to launch the agent. + +--- + +### 2. Prompt-Based Coding + +When you ask something in plain English, Warp’s agent automatically: + +* Gathers relevant context (your repo, files, or command output) +* Runs whatever commands are needed +* Returns a structured answer or takes the requested action + +Example: + +> “Describe my open git changes.” + +Warp’s agent will review your current branch, run git commands in the background, and summarize what’s pending. + +--- + +### 3. Blending Terminal and Agentic Workflows + +The beauty of Warp is in how seamlessly it blends traditional CLI workflows with AI-driven automation.\ +You can: + +* Type commands like a normal shell +* Or prompt an agent to do things like debugging, code review, or environment setup + +No context-switching between apps — it’s all one environment. diff --git a/src/content/docs/guides/index.mdx b/src/content/docs/guides/index.mdx new file mode 100644 index 0000000..6df8c5c --- /dev/null +++ b/src/content/docs/guides/index.mdx @@ -0,0 +1,35 @@ +--- +title: Guides +description: >- + Step-by-step guides for Warp, the agentic development environment — from + first setup to coding agent workflows, MCP integrations, and full app + builds. +--- + +Practical, task-oriented walkthroughs that help you get productive with Warp's coding agents. Each guide walks through a real AI coding workflow with actual prompts, code, and reproducible results. + +Browse by topic in the sidebar, or start with one of these featured guides. + +:::note +**New to Warp?** Start with [Welcome to Warp](/guides/getting-started/welcome-to-warp/), then explore [10 Warp Coding Features You Should Know](/guides/getting-started/10-coding-features-you-should-know/). +::: + +## Featured guides + +- [**Explain your codebase with agents**](/guides/agent-workflows/how-to-explain-your-codebase-using-warp-rust-codebase/) — Use semantic and symbol search to explore and understand unfamiliar code. +- [**Create project rules**](/guides/configuration/how-to-create-project-rules-for-an-existing-project-astro-typescript-tailwind/) — Set up an AGENTS.md file so coding agents always understand your project’s setup and conventions. +- [**Fix errors with Sentry MCP**](/guides/external-tools/sentry-mcp-fix-sentry-error-in-empower-website/) — Connect the Sentry MCP server to Warp and auto-diagnose production errors. +- [**Run multiple agents in parallel**](/guides/agent-workflows/how-to-run-3-agents-in-parallel-summarize-logs-analyze-pr-modify-ui/) — Work on coding, debugging, and analysis tasks simultaneously across tabs. +- [**Build a real-time chat app**](/guides/build-an-app-in-warp/building-a-real-time-chat-app-github-mcp-railway/) — Go from idea to deployed app with FastAPI, JavaScript, and GitHub MCP — all inside Warp. +- [**Connect agents to external tools**](/guides/external-tools/using-mcp-servers-with-warp/) — Set up MCP servers to give agents access to Linear, GitHub, Figma, and more. + +## What’s in this section + +* **Getting started** — First steps with Warp: setup, appearance, key features +* **Agent workflows** — Use coding agents to explain code, review PRs, and run parallel tasks +* **Configuration** — Rules, agent profiles, saved prompts, and monorepo sync +* **External tools & integrations** — Connect coding agents to Sentry, Figma, Linear, GitHub, and more via MCP +* **Build an app in Warp** — End-to-end app builds with AI coding workflows: chat apps, Chrome extensions, Slackbots +* **DevOps & infrastructure** — Agent-assisted cloud logs, Docker, Kubernetes, testing, and database optimization +* **Frontend & UI** — Build and refine UI components with coding agents + diff --git a/src/content/docs/index.mdx b/src/content/docs/index.mdx new file mode 100644 index 0000000..91e6eb9 --- /dev/null +++ b/src/content/docs/index.mdx @@ -0,0 +1,106 @@ +--- +title: Getting started with Warp and Oz +description: >- + Get started with Warp, the Agentic Development Environment, and Oz, the + orchestration platform for cloud agents. +sidebar: + label: Getting started with Warp and Oz +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +Warp is an [open source](https://github.com/warpdotdev/warp) **Agentic Development Environment**, a modern terminal combined with powerful agents that help you build, test, deploy, and debug code. Warp's AI is powered by **Oz**, the orchestration platform for cloud agents. + +![Warp, the Agentic Development Environment: Warp (a modern terminal built for coding with agents) and Oz (the orchestration platform for cloud agents)](../../assets/terminal/warp-oz-welcome.png) + +--- + +## Warp + +Warp is where you work — a fast, modern terminal built for coding with agents. + +**Key capabilities:** + +* [**Terminal and Agent modes**](/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes/): Switch between a clean terminal for commands and a dedicated conversation view for multi-turn agent workflows. +* [**Modern terminal UX**](/terminal/editor/): Cursor movement, block-based navigation, multi-line editing, syntax highlighting, and rich completions. Built with Rust for high performance. +* [**Code editor**](/code/overview/): File tree, code editor with LSP support, and interactive code review experience. +* [**Third-Party CLI Agents**](/agent-platform/cli-agents/overview/): Run third-party CLI agents like Claude Code, Codex, and OpenCode with Warp's agent toolbelt — rich input, code review, notifications, and more. + +<VideoEmbed url="https://www.youtube.com/watch?v=xhkoXsE9Wqc" title="Deep dive into Warp's core features" /> + +--- + +## Oz: The orchestration platform for cloud agents + +Oz is the orchestration platform for cloud agents that powers all of Warp's intelligent features. Oz is designed to coordinate agents at scale—understanding your codebase, executing tasks autonomously, and adapting to your workflows. Oz is multi-model by design, giving you flexibility to choose the best LLM for each task. + +Oz operates in two modes: + +### Local agents + +Run directly in the Warp app for real-time, interactive coding assistance. + +* Write and refactor code across your codebase +* Debug issues and fix errors +* Run commands and interpret results +* Plan and execute multi-step tasks + +Local agents keep you in control. You can review changes, steer the agent mid-task, and approve actions before they execute. + +→ [Get started with local agents](/agent-platform/local-agents/overview/) + +### Cloud agents + +Oz Cloud Agents run in the background on Warp's infrastructure (or your own) for automation at scale. + +* **Triggers**: React to events from Slack, Linear, GitHub, or custom webhooks +* **Schedules**: Run recurring tasks like dependency updates or dead code removal +* **Parallelism**: Run many agents concurrently across repos or tasks +* **Observability**: Every run is tracked, auditable, and shareable with your team + +Cloud agents are ideal for work that doesn't need your immediate attention, like PR reviews, issue triage, routine maintenance, and integration-driven workflows. + +→ [Learn about cloud agents](/agent-platform/cloud-agents/overview/) + +--- + +## How they work together + +Warp and Oz provide a unified experience across local and cloud development: + +* **Same agent, anywhere**: Whether you're working interactively in Warp or running agents in the cloud, you're using the same underlying agent capabilities. +* **Seamless handoff**: Start a task in the cloud and take over locally in Warp when you want hands-on control, without losing progress or context. +* **Shared context**: [Warp Drive](/knowledge-and-collaboration/warp-drive/), [Rules](/agent-platform/capabilities/rules/), and [MCP servers](/agent-platform/capabilities/mcp/) work across both local and cloud agents, so your team's knowledge and tools are always available. +* **Team collaboration**: Share agent sessions, review agents' actions, and steer running tasks, regardless of who started them. + +--- + +## Multi-model support + +Oz is multi-model by design. You can [choose your preferred LLM](/agent-platform/capabilities/model-choice/) from a curated set of top models. + +--- + +## Open source + +Warp's client is open source under [AGPL v3](https://github.com/warpdotdev/warp/blob/master/LICENSE). The source lives at [`warpdotdev/warp`](https://github.com/warpdotdev/warp), where you can read the code, file issues, and contribute alongside the Warp team. Development happens in the open with an agent-first workflow managed by Oz. + +→ [Contributing to Warp](/support-and-community/community/contributing/) explains how to file issues, claim work, and ship code or themes. + +--- + +## Privacy and security + +Warp is **SOC 2 compliant** and has **Zero Data Retention** policies with all contracted LLM providers. No customer AI data is retained, stored, or used for training. + +Warp's AI features can be globally disabled in **Settings** > **Agents** > **Warp Agent**. + +→ [Read more about data privacy](https://www.warp.dev/privacy) + +--- + +## Next steps + +* [**Quickstart**](/quickstart/): Get Warp installed and start coding +* [**Warp Agents overview**](/agent-platform/local-agents/overview/): Explore all AI features available in Warp +* [**Cloud Agents Overview**](/agent-platform/cloud-agents/overview/): Set up background automation +* [**Oz Platform**](/agent-platform/cloud-agents/platform/): Learn about the CLI, API, SDK, and infrastructure diff --git a/src/content/docs/knowledge-and-collaboration/admin-panel.mdx b/src/content/docs/knowledge-and-collaboration/admin-panel.mdx new file mode 100644 index 0000000..d03f3fa --- /dev/null +++ b/src/content/docs/knowledge-and-collaboration/admin-panel.mdx @@ -0,0 +1,184 @@ +--- +title: Team Admin Panel +description: >- + Centralized management for team administrators to configure workspace + settings enforced across all team members. +--- + +## What is the Admin Panel? + +The [Admin Panel](https://app.warp.dev/admin/) provides team administrators with centralized control over organization-wide settings in Warp. It allows you to manage workspace settings that are enforced across all members of your team. + +:::note +Admin Panel access is restricted to team administrators. Right now, only the creator of a team is the designated admin. If your admin has setup styles that override user preferences, you will not be able to control them inside of Warp, and you'll see a note that your admin has configured this setting. +::: + +**Key features:** + +* **AI Settings** - Control agent autonomy, permissions, and allowlists across your team +* **Privacy Controls** - Configure data collection and enterprise secret redaction +* **Billing Management** - Set spending limits and manage usage-based pricing +* **Code Settings** - Control codebase indexing and context features +* **Sharing Policies** - Manage link sharing and collaboration permissions + +## Accessing the Admin Panel + +Team administrators can access the Admin Panel directly at https://app.warp.dev/admin/ + +![Admin Panel main interface with sections for AI, privacy, billing, code, and sharing settings](../../../assets/terminal/admin-panel-overview.png) + +## How settings enforcement works + +The Admin Panel uses a tier-based policy system to determine which settings administrators can control: + +### Toggleable vs. fixed settings + +**Toggleable settings** can be modified by team administrators. These appear as dropdown menus with options like: + +* Enabled/Disabled for boolean settings +* Specific autonomy levels for AI settings +* Respect User Setting to allow individual control + +**Fixed settings** are determined by your billing tier and cannot be changed. These appear with a message: "Configuring this setting is not available on your plan." + +### Setting Inheritance + +When administrators configure organization-wide settings: + +1. **Organization enforced** - Setting applies to all team members regardless of individual preferences +2. **Respect user setting** - Allows individual team members to control the setting themselves +3. **Tier restricted** - Setting is locked to default values based on billing plan + +### User Experience + +:::note +Any changes made in the Admin Panel can take effect immediately for all team members. Consider testing settings in Warp before applying organization-wide policies. +::: + +When organization settings override individual preferences: + +* Users see their personal settings grayed out +* A message indicates "your organization has configured this setting" +* Users cannot modify settings that are organizationally enforced + +## Plan Limitations + +The features available in the Admin Panel vary by billing tier: + +**Free Tier** + +* Most settings are fixed and non-toggleable +* Limited Codebase Context and sharing features + +**Business Plans** + +* Most settings become toggleable by administrators +* Enhanced AI autonomy control +* Advanced sharing and privacy features + +**Enterprise Plans** + +* Full admin control over all settings +* Enterprise secret redaction +* Custom LLM integration +* Advanced compliance features + +For complete details about what's included in each plan, visit [warp.dev/pricing](https://www.warp.dev/pricing). + +## Admin Panel sections + +The Admin Panel is organized into five main sections, each focused on a specific area of team management: + +### AI Settings + +Configure how Agents behave across your organization, including autonomy levels and command permissions. + +#### General AI Settings + +**AI in Remote Sessions** Controls whether AI features are available during SSH sessions and remote connections. Enterprise plans can toggle this setting, while Free tier teams have it enabled by default. + +**Prompt Summarization Caching** When conversations become long enough to require summarization, this setting allows the summary to be cached temporarily by the LLM provider to improve performance. + +#### Autonomy Settings + +Configure how much independence Agents have when performing different actions: + +**Apply Code Diffs** + +* Agent Decides - Prompt for review before applying code diffs (currently behaves the same as Always Ask) +* Always Ask - Require explicit approval before applying any code changes +* Always Allow - Apply code diffs without confirmation +* Respect User Setting - Allow individual users to control this setting + +**Create Plans** Controls whether Agents can create structured task plans without user approval. + +**Execute Commands** Manages Agent's ability to run terminal commands autonomously. + +**Read Files** Controls Agent access to reading files in the codebase. + +#### Directory and Command Control + +**Directory Allowlist** Specify directories where Agents can read files without restriction. Use paths like `~/git/repo1` to grant access to specific project folders. + +**Command Allowlist** Regular expressions matching commands that Agent Mode can execute without asking permission. Common examples: + +* `grep .*` - Text search commands +* `ls(\\s.*)?` - Directory listing +* `which .*` - Finding executable locations + +**Command Denylist** Regular expressions for commands that always require explicit user approval, even if they would normally be allowed. Examples: + +* `rm -rf.*` - Recursive file deletion +* `sudo.*` - Administrative commands +* `curl.*` - Network requests + +:::caution +Command denylist rules take precedence over allowlist rules and agent autonomy settings. If a command matches the denylist, user permission will always be required. +::: + +### Privacy Settings + +Manage data collection and security policies for your organization. + +**UGC Data Collection** Controls how Warp collects and uses user-generated content to improve the service: + +* Disabled - No UGC data collection +* Enabled - Allow data collection for service improvement +* Respect User Setting - Let individual users decide + +**Enterprise Secret Redaction** When enabled, applies regex patterns to prevent secrets from being sent to Warp servers or LLM providers. This feature is available on Enterprise plans and includes: + +* Automatic detection of common secret patterns +* Custom regex patterns for organization-specific secrets +* Unconditional application across all team members + +### Code Settings + +Control codebase indexing and AI code features for your team. + +**Codebase Context** Determines whether Warp indexes your team's Git repositories to provide context for AI features: + +* Disabled - No codebase indexing +* Enabled - Index codebases for improved AI responses +* Respect User Setting - Allow individual control + +Higher tier plans support more indexed repositories and larger file limits per codebase. + +### Billing Settings + +Configure billing preferences and spending controls. + +**Usage Based Pricing** Enable pay-as-you-go billing for credits beyond your plan's included quota. When enabled, you can set: + +**Monthly Spending Limit** Set a maximum monthly overage spending limit to control costs. The system displays current overage usage including: + +* Total overage credits used +* Current month's overage costs + +### Sharing Settings + +Control how team members can share Warp Drive objects and collaborate. + +**Direct Link Sharing** Allow team members to share Notebooks, Workflows, and other objects via direct links. + +**Anyone with Link Sharing** Enable public access to shared objects - anyone with the link can view the content without being a team member. diff --git a/src/content/docs/knowledge-and-collaboration/session-sharing/index.mdx b/src/content/docs/knowledge-and-collaboration/session-sharing/index.mdx new file mode 100644 index 0000000..d45cfb2 --- /dev/null +++ b/src/content/docs/knowledge-and-collaboration/session-sharing/index.mdx @@ -0,0 +1,11 @@ +--- +title: Session Sharing +description: >- + Share terminal sessions with teammates for collaboration, debugging, and + knowledge sharing. +--- + +Session sharing documentation has moved to the Agent Platform section. See the articles below for details on sharing sessions: + +* **[Agent Session Sharing](/agent-platform/local-agents/session-sharing/)** - Share agent sessions with your team for review and collaboration. +* **[Viewing Cloud Agent Runs](/agent-platform/cloud-agents/viewing-cloud-agent-runs/)** - Share session context from cloud agent runs. diff --git a/src/content/docs/knowledge-and-collaboration/teams.mdx b/src/content/docs/knowledge-and-collaboration/teams.mdx new file mode 100644 index 0000000..759da1a --- /dev/null +++ b/src/content/docs/knowledge-and-collaboration/teams.mdx @@ -0,0 +1,93 @@ +--- +title: Team management +description: >- + Create or join a team to collaborate with others in Warp. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +## What is a team? + +A team is a group of Warp users who can collaborate on the command line together. Warp teams can share a dedicated workspace in Warp Drive. [Learn about pricing](https://www.warp.dev/pricing) and see our [Pricing FAQ](/support-and-community/plans-and-billing/pricing-faqs/). + +:::note +Currently, each Warp user can only be an admin or member of one team at a time. +::: + +<VideoEmbed url="https://www.youtube.com/watch?v=8UmreUTTrkg&start=199s&end=277s" title="Teams Demo" /> + +## Creating a team + +You can create a new team in the following ways: + +* Warp Drive, + Create a team +* **Settings** > **Teams** + +Before you can invite team members, you will need to give your team a meaningful name. We suggest using a name to represent your organization, company, or project. + +:::note +You can rename the team by going to **Settings** > **Teams** and clicking on the team name, entering the new name, and pressing `ENTER` to accept. +::: + +![Teams settings panel with a team name input field and Create button](../../../assets/terminal/team-creation-settings.png) + +If you create a team, you become the team’s admin and will be the only person who can delete the team. Reference [Team roles and permissions](/knowledge-and-collaboration/teams/#team-roles-and-permissions) for more info. + +### Inviting new team members + +Under **Settings** > **Teams** you can copy the invite link for your Warp team and paste it to your clipboard. + +:::caution +If you’re on a paid plan, upgrading will automatically include all team members in your billing. Adding new members after upgrading will also add them as paid seats. + +For more details on how team member billing works, please see our [billing FAQs](/support-and-community/plans-and-billing/pricing-faqs/#what-counts-as-a-team-member-and-how-does-billing-work-for-members). +::: + +![Teams settings panel](../../../assets/terminal/teams-invite-demo.png) + +When you share this link with your teammates directly (we suggest using a secure channel like Slack or email), they will be able to join your team in Warp. + +## Restricting team invites by domain + +Sometimes you may want to control your team so that people can only join if they also authenticate with a specific email domain, such as your company’s email domain. + +Toggle on Restrict by domain to set an explicit allowlist. + +If you share an invite link with somebody who’s using Warp with a domain that does not match your allowlist, they will be prompted to authenticate from an emailed link sent to a matching domain to join your team. + +## Joining a team + +If you have received an invite link, you can use that link to sign up or log in and join your team in Warp. If your team is using domain restriction, you will need to authenticate you have access to a specific domain before you can join your team. + +## Leaving and deleting teams + +If you’re a member of a team, you can visit **Settings** > **Teams** to leave a team at any time. Team admins (who created teams) may delete a team only after removing all team members. + +## Team discoverability + +Team admins can make their teams discoverable to colleagues from the same email domain. This feature is available under **Settings** > **Teams** > **Make team discoverable**. + +:::note +While discoverability is enabled, any new user who joins the team will add a prorated charge to the team's next month's bill. See more in our [pricing docs](/support-and-community/plans-and-billing/pricing-faqs/#what-counts-as-a-team-member-and-how-does-billing-work-for-members). +::: + +## Transferring team admin + +Team admins can transfer their role to another team member by going to **Settings** > **Teams** > **Transfer admin** and selecting the member to whom you'd like to transfer the admin role. + +## Team roles and permissions + +:::caution +If you're a Team admin, and you choose to [delete your Warp](/support-and-community/privacy-and-security/privacy/#manage-your-data) account, the deletion flow will require that you assign a team member as the new admin. +::: + +| | Admin | Member | +| ------------------------------------------------------------- | ---------------------------------------------------------------- | -------------------------------------- | +| | This is the Warp user who created a team. There can only be one. | All team members who belong to a team. | +| Create a team | ✓ | | +| Restrict by domain | ✓ | | +| Invite members | ✓ | ✓ | +| Remove team members | ✓ | | +| Leave a team | | ✓ | +| Delete a team | ✓ | | +| Transfer admin | ✓ | | +| [Manage billing](/support-and-community/plans-and-billing/plans-pricing-refunds/) | ✓ | | diff --git a/src/content/docs/knowledge-and-collaboration/warp-drive/agent-mode-context.mdx b/src/content/docs/knowledge-and-collaboration/warp-drive/agent-mode-context.mdx new file mode 100644 index 0000000..541831a --- /dev/null +++ b/src/content/docs/knowledge-and-collaboration/warp-drive/agent-mode-context.mdx @@ -0,0 +1,28 @@ +--- +title: Agent Mode Context +description: >- + Agents use your Warp Drive content—Workflows, Notebooks, Rules, MCP Servers, + and Environment Variables—for context-aware responses. +--- + +[Agent Mode](/agent-platform/local-agents/interacting-with-agents/) can leverage your [Warp Drive](/knowledge-and-collaboration/warp-drive/) contents to tailor responses to your personal and team developer workflows and environments. + +## Objects used as context + +Agents can automatically pull in relevant context from: + +* **Workflows** - Saved commands and scripts +* **Notebooks** - Documentation and notes +* **Environment Variables** - Configuration values +* **Rules** - Guidelines that shape agent behavior (see [Rules](/agent-platform/capabilities/rules/)) +* **MCP Servers** - External tools and data sources (see [MCP](/agent-platform/capabilities/mcp/)) + +When a Warp Drive object is pulled as context, it will be displayed in the conversation as a citation under "References" or "Derived from". + +## Settings + +Enabled by default, this can be toggled in **Settings** > **Agents** > **Knowledge** > **Warp Drive as Agent Mode Context**. + +## Related + +* [AI-Integrated Objects](/knowledge-and-collaboration/warp-drive/ai-objects/) - Overview of all AI-related objects in Warp Drive diff --git a/src/content/docs/knowledge-and-collaboration/warp-drive/ai-objects.mdx b/src/content/docs/knowledge-and-collaboration/warp-drive/ai-objects.mdx new file mode 100644 index 0000000..9d24241 --- /dev/null +++ b/src/content/docs/knowledge-and-collaboration/warp-drive/ai-objects.mdx @@ -0,0 +1,84 @@ +--- +title: AI-Integrated Objects +description: >- + Access Rules, MCP Servers, Skills, and Prompts in Warp Drive to give agents + personalized context. +--- + +Warp Drive includes several object types that integrate with Warp's agents to provide personalized, context-aware assistance. These objects help agents understand your coding standards, connect to external tools, and follow your preferred workflows. + +## Rules + +Rules are reusable guidelines that inform how agents respond to your prompts. They help tailor responses to match your coding standards, project conventions, and personal preferences. + +**Access from Warp Drive:** **Personal** > **Rules** + +Warp supports two types of rules: + +* **Global Rules** - Apply across all projects and contexts +* **Project Rules** - Live in your codebase (as `AGENTS.md` or `WARP.md` files) and apply automatically when working within that project + +:::note +For complete documentation on creating and managing rules, see [Rules](/agent-platform/capabilities/rules/). +::: + +## MCP Servers + +MCP (Model Context Protocol) servers extend Warp's agents with custom tools and data sources through a standardized interface. They act as plugins that let agents access external services like GitHub, Sentry, Linear, Slack, and more. + +**Access from Warp Drive:** **Personal** > **MCP Servers** + +MCP servers can be: + +* **CLI-based** - Local commands that Warp launches and manages +* **URL-based** - Remote endpoints using Streamable HTTP or SSE + +:::note +For complete documentation on configuring and using MCP servers, see [Model Context Protocol (MCP)](/agent-platform/capabilities/mcp/). +::: + +## Skills + +Skills are reusable instruction sets that teach agents how to perform specific tasks. Unlike Rules (which provide guidelines), Skills define complete workflows that agents can invoke when relevant. + +Skills are file-based (stored as `SKILL.md` files in your project or home directory) rather than cloud-synced objects, but they integrate closely with Warp Drive workflows. + +* **Project Skills** - Live in `.agents/skills/`, `.warp/skills/`, or similar directories in your repository +* **Global Skills** - Live in `~/.agents/skills/` or similar directories in your home folder + +:::note +For complete documentation on creating and using skills, see [Skills](/agent-platform/capabilities/skills/). +::: + +## Prompts + +Prompts are parameterized natural language queries you can save and reuse with Agent Mode. They allow you to save complex AI workflows and execute them quickly from the Command Palette. + +**Access from Warp Drive:** Click **+** and select "Prompt", or browse existing prompts in your personal or team workspace. + +:::note +For complete documentation on Prompts, see [Prompts](/knowledge-and-collaboration/warp-drive/prompts/). +::: + +## How agents use these objects + +When you start an agent conversation, Warp automatically provides relevant context from your Warp Drive objects: + +* **Rules** guide agent behavior and responses based on your preferences +* **MCP Servers** give agents access to external tools and data sources +* **Skills** provide task-specific instructions agents can invoke +* **Prompts** let you trigger predefined workflows quickly + +When an object is used as context, it appears in the conversation under "References" or "Derived from." + +:::note +For more details on how Warp Drive content serves as agent context, see [Warp Drive as Agent Mode Context](/knowledge-and-collaboration/warp-drive/agent-mode-context/). +::: + +## Related + +* [Rules](/agent-platform/capabilities/rules/) - Create guidelines for agent behavior +* [MCP Servers](/agent-platform/capabilities/mcp/) - Connect external tools and data sources +* [Skills](/agent-platform/capabilities/skills/) - Define reusable task workflows +* [Prompts](/knowledge-and-collaboration/warp-drive/prompts/) - Save and reuse parameterized agent prompts +* [Agent Profiles & Permissions](/agent-platform/capabilities/agent-profiles-permissions/) - Control agent autonomy and tool access diff --git a/src/content/docs/knowledge-and-collaboration/warp-drive/environment-variables.mdx b/src/content/docs/knowledge-and-collaboration/warp-drive/environment-variables.mdx new file mode 100644 index 0000000..c4f893e --- /dev/null +++ b/src/content/docs/knowledge-and-collaboration/warp-drive/environment-variables.mdx @@ -0,0 +1,141 @@ +--- +title: Environment variables +description: >- + Save or sync environment variables to load into your terminal sessions. +--- + +## What are environment variables in Warp? + +Environment variables in Warp are similar to .env files, except you can: + +* Load them into your terminal session with a click. +* Use them in parameterized workflows. +* Dynamically reference secrets from external managers. + +## How to create and edit environment variables + +You can create new environment variables through: + +* [Warp Drive](/knowledge-and-collaboration/warp-drive/), + → Environment variable +* [Command Palette](/terminal/command-palette/), create new team or personal environment variables + +Any of these entry points will open the environment variables editor where you can name and describe your environment variables. + +![Environment variable editor in Warp Drive showing fields for name and description.](../../../../assets/terminal/env-var-create.png) + +## Managing individual environment variables + +Warp supports two types of environment variables: static variables and dynamic variables. + +### Static variables + +Static variables are similar to .env files. You create the variables by entering raw strings of text. Each variable has a variable name and a corresponding value. + +![Saving a static environment variable with name and value pairs.](../../../../assets/terminal/env-var-static-variable-save.png) + +After you save the environment variable, you can click it to load it into your terminal session. + +![Loading a saved static environment variable into the current terminal session.](../../../../assets/terminal/env-var-static-variable-load.png) + +When you use static variables, Warp stores them securely in Warp Drive.\ +\ +Note: Static variables should not be used to replace a secret manager. Please use dynamic variables for any sensitive information. + +### Dynamic variables + +:::note +Warp never stores secrets used in dynamic variables. Warp only stores the command used to dynamically retrieve the secrets at runtime. +::: + +Dynamic variables let you reference secrets that are stored securely outside of Warp in external secret managers, such as 1Password or LastPass. + +You can use custom commands to create dynamic variables for any system with a public API or CLI, such as AWS or Hashicorp Vault. + +### **How to create and edit dynamic environment variables** + +To create a new dynamic variable: + +1. Open the environment variable editor. +2. Use the key icon to reveal the dynamic variable menu. +3. Select an integrated password manager or "Command" to write your own custom integration. + +![Opening the dynamic environment variable menu via the key icon in the editor.](../../../../assets/terminal/env-var-dynamic-variables.png) + +#### **Integrated password managers** + +Before you get started, please ensure you have the CLI installed for your tool of choice and follow the instructions to enable the CLI: + +* [1Password CLI](https://developer.1password.com/docs/cli/get-started/) +* [LastPass CLI](https://github.com/lastpass/lastpass-cli) + +Then, you can click the key icon and select your manager from the dropdown menu. + +![Selecting an integrated password manager from the dynamic variable dropdown.](../../../../assets/terminal/env-var-password-mgrs.png) + +The CLI will require you to authenticate and then provide you with a list of available secrets. + +:::note +Selecting a secret name never stores the actual secret. Warp uses your selection to generate a command that dynamically pulls in your selected secret at runtime. +::: + +![Selecting a secret name from the password manager CLI's available list of secrets.](https://lh7-rt.googleusercontent.com/docsz/AD_4nXcqiazhpRvaHxxSW5n3Ql6nFRDDRkyVdlRB9E-Q6HE0lpL2KFgwLM1P1PPrJG_i0KIHWuEKp2PMFq4T1auWvQOxXrpuERpLRZG1h2V4DDYmNRZRqShxjPzWyqGR2VfXYNhttAK0HT2-aQNjAt3xdCA9MwE?key=q_xMyXgvJVA02ysqZAH4Jw) + +### **How to write a custom secret command** + +Reference the documentation for your external secret manager. Then, write a custom command to retrieve secrets. + +:::note +Your custom command should return the exact string you want loaded into your environment. Please make sure that you are selecting the exact field you want loaded as many secret manager CLIs provide additional formatting by default. +::: + +For example, you can write a command using the [Hashicorp Vault CLI](https://developer.hashicorp.com/vault/docs/commands) to retrieve and load the password field for the staging server. When using secret commands, Warp stores the command but never the actual secrets. The secrets are referenced and loaded into a terminal session at runtime. + +``` +// vault kv get -field=password secret/staging/app/server/creds +``` + +![Custom command using the Hashicorp Vault CLI to retrieve a password field at runtime.](https://lh7-rt.googleusercontent.com/docsz/AD_4nXcltckpSwesjA1O84nzZhUKc0Wuie0OH3iN6g0WPBojhtY5pckPSZgOZxqIjiV12ppe9t0jtF9z2Yf7d-fIZJhSu8-tLIT8CoG_Xh_NvCzFbrJgD5FA2ounNtHurq9nDLALiOekjPeVoru-FzeYOWkfm9PN?key=q_xMyXgvJVA02ysqZAH4Jw) + +### Using environment variables + +There are three ways to invoke your environment variables and load them into a terminal session: + +1. [Click to load into a current section](/knowledge-and-collaboration/warp-drive/environment-variables/#click-to-load-into-a-current-session) +2. [Click to load into a subshell](/knowledge-and-collaboration/warp-drive/environment-variables/#click-to-load-into-a-subshell) +3. [Select to load in with a workflow](/knowledge-and-collaboration/warp-drive/environment-variables/#select-to-load-with-a-workflow) + +#### Click to load into a current session + +First, click your environment variable from Warp Drive or the Command Palette. + +Then, review the confirmation block. If your environment variables are correct, hit enter to load them into your session. + +![Confirmation block prompting to load environment variables into the current session.](../../../../assets/terminal/env-var-load-to-input-1.png) + +![Environment variables successfully loaded into the current terminal session.](../../../../assets/terminal/env-var-load-in-session.png) + +These environment variables will now be present for the remainder of your session. + +#### Click to load into a subshell + +To load environment variables into a subshell, you will need to open [Warp Drive](/knowledge-and-collaboration/warp-drive/) and locate your environment variable in the Warp Drive index. You can then use the overflow menu to select "Load in subshell." + +Loading an environment into a subshell reduces the risk of your environment variables accidentally contaminating your workspace. The subshell is clearly defined and once you exit it, any environment variables set by Warp Environment Variables will be cleared, unless they are already present in the parent session. + +![Selecting Load in subshell from an environment variable's overflow menu in Warp Drive.](https://lh7-rt.googleusercontent.com/docsz/AD_4nXeqhj2saz5AJTYUCx-PClwCLX421mKEzXelcnnkeHkqvDexelvBDmPpESHOmV_SjAOEuLKk8YgYaIodX-cOuXm1Nm05wUU88zcIv3otd1HRvXO455EiKEfs5tTB5ft9OoW7qxMK9BV1OPAVIc9AhMqsgweK?key=q_xMyXgvJVA02ysqZAH4Jw) + +![Environment variables loaded into a subshell, isolated from the parent terminal session.](https://lh7-rt.googleusercontent.com/docsz/AD_4nXeeXyJEMxJV2DpOBJS7pKOEpBSm6aypAIKd4ygJKT13opDBxeS5k0S5NtM8Cr_Z_lafyj-cn1T-hJ-93AkZhpWTrbvYHYIRs96_V7dr3mfiM3lPx6-kMS_eLjINPHIr6Ex0NaMr-TRCkNQ1fdVv8cApJ0QJ?key=q_xMyXgvJVA02ysqZAH4Jw) + +#### Select to load with a workflow + +Any time you run a workflow, you can select from existing environment variables. This allows you to dynamically inject environment variables into a parameterized workflow so you can use a single workflow command in multiple environments, such as production and staging. + +For example, you may have a workflow to create a new team that uses the environment variable $SERVER\_URL. By using the environment variables dropdown in the workflow card, you can dynamically inject the necessary variables. This ensures the workflow references the appropriate values so the command runs with the relevant environment-specific information. + +These environment variables will now be present for the remainder of your session until you clear them or overwrite them with a different environment. + +![Selecting environment variables from the dropdown when running a parameterized workflow.](https://lh7-rt.googleusercontent.com/docsz/AD_4nXcuOxH8UeVLSvWRpZwvdoVBgbpFhb2rXKbDw2CnZ5BQCTWSgzjwERe-fzKLEYBQZGKzjV-Pdd_z6tB9BTSWYos9ADRaDbChskSg-MZpjaKme0kG8UwWsJ2HBJk7iBu4SKbGZCobZy0uD2nFkrNoVjNZEEOW?key=q_xMyXgvJVA02ysqZAH4Jw) + +### Import and export environment variables in Warp Drive + +Please see our [Warp Drive Import and Export](/knowledge-and-collaboration/warp-drive/#import-and-export) instructions. diff --git a/src/content/docs/knowledge-and-collaboration/warp-drive/index.mdx b/src/content/docs/knowledge-and-collaboration/warp-drive/index.mdx new file mode 100644 index 0000000..149035c --- /dev/null +++ b/src/content/docs/knowledge-and-collaboration/warp-drive/index.mdx @@ -0,0 +1,170 @@ +--- +title: Warp Drive overview +description: >- + Warp Drive is a workspace in your terminal where you can save Workflows, + Notebooks, Prompts, and Environment Variables for personal use or to share + with a team. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +## What is Warp Drive? + +All objects stored in Warp Drive sync immediately as they’re updated, so you and your team will always have access to the latest versions. + +<VideoEmbed url="https://youtu.be/AGL0YcRj5-o" title="Warp Drive Overview" /> + +## How to access it + +<Tabs> + <TabItem label="macOS"> + Warp Drive is accessible from the status bar in Warp or you can toggle the Warp Drive side panel with `CMD-\`. + </TabItem> + <TabItem label="Windows"> + Warp Drive is accessible from the status bar in Warp or you can toggle the Warp Drive side panel with `CTRL-SHIFT-\`. + </TabItem> + <TabItem label="Linux"> + Warp Drive is accessible from the status bar in Warp or you can toggle the Warp Drive side panel with `CTRL-SHIFT-\`. + </TabItem> +</Tabs> + +![Warp Drive icon on top left corner of Warp](../../../../assets/terminal/Open_Warp_Drive.png) + +## Workspaces in Warp Drive + +When you open the Warp Drive panel, you will find a personal workspace where you can store your Workflows, Notebooks, Prompts, and Environment Variables and organize them into folders. + +![Personal workspace zero state in Warp Drive, showing where Workflows, Notebooks, Prompts, and Environment Variables are saved.](../../../../assets/terminal/Warp_Drive_Zero_State.png) + +If you are a member of a team using Warp Drive, your team’s workspace will also be available in the side panel. + +![Warp Drive side panel showing both a personal workspace and a team workspace.](../../../../assets/terminal/Warp_Drive_with_Team.png) + +## Organizing objects in Warp Drive with your team + +* Objects (e.g. Workflows, Notebooks, Prompts, and Environment Variables) and folders in Warp Drive can be sorted alphabetically and by the last updated +* Any objects moved from your personal workspace into a team’s workspace will be shared with all members of your team +* It is not currently possible to move an item back from a team’s workspace into a personal workspace; if you shared something inadvertently, you should copy the contents of the object to your clipboard, recreate it in your personal workspace, and then delete the object from your team workspace +* It is not currently possible to drag a folder of personal Workflows into a team workspace; you will need to move objects one at a time + +## Using Warp Drive offline + +In offline mode, some files will be read-only. You can still create and edit files while offline in your personal space. They will only be saved locally and will not be synced. They cannot be moved into a team or deleted until you are back online. + +![Warp Drive offline mode](../../../../assets/terminal/warp_drive_offline.png) + +## Navigating Warp Drive with your keyboard + +To avoid going back and forth between your mouse and keyboard, you can use your keyboard to navigate through Warp Drive once you have either opened Warp Drive or switched focus to the Warp Drive panel. (You can also click on a blank area within Warp Drive.) The object you are navigating with your keyboard will be highlighted in an accented color. + +You can take these keyboard actions within Warp Drive: + +<Tabs> + <TabItem label="macOS"> + * Press `UP`/`DOWN` or `j`/`k` to navigate to the object you want. + * Press `Enter` to 1) execute an object, 2) open/collapse a workspace or folder, or 3) open the trash. + * Press `CMD-ENTER` to open an object’s context menu. + * Press `CMD-SHIFT-(` and `CMD-SHIFT-)` to switch focus between the terminal and Warp Drive. + * Press `LEFT-ARROW` to collapse a workspace or folder + * Press `RIGHT-ARROW` to open a workspace or folder + * Press `Esc` to return to Warp Drive from your trash. + </TabItem> + <TabItem label="Windows"> + * Press `UP`/`DOWN` or `j`/`k` to navigate to the object you want. + * Press `Enter` to 1) execute an object, 2) open/collapse a workspace or folder, or 3) open the trash. + * Press `CTRL-ENTER` to open an object’s context menu. + * Press `CTRL-SHIFT-(` and `CTRL-SHIFT-)` to switch focus between the terminal and Warp Drive. + * Press `LEFT-ARROW` to collapse a workspace or folder + * Press `RIGHT-ARROW` to open a workspace or folder + * Press `Esc` to return to Warp Drive from your trash. + </TabItem> + <TabItem label="Linux"> + * Press `UP`/`DOWN` or `j`/`k` to navigate to the object you want. + * Press `Enter` to 1) execute an object, 2) open/collapse a workspace or folder, or 3) open the trash. + * Press `CTRL-ENTER` to open an object’s context menu. + * Press `CTRL-SHIFT-(` and `CTRL-SHIFT-)` to switch focus between the terminal and Warp Drive. + * Press `LEFT-ARROW` to collapse a workspace or folder + * Press `RIGHT-ARROW` to open a workspace or folder + * Press `Esc` to return to Warp Drive from your trash. + </TabItem> +</Tabs> + +![Warp Drive navigation states](../../../../assets/terminal/warp_drive_nav1.png) + +To switch between panels using your keyboard, you can use the “Switch Focus to Left Panel” and “Switch Focus to Right Panel” commands in the [Command Palette](/terminal/command-palette/). + +![Switching focus between the terminal and Warp Drive panels via the Command Palette.](../../../../assets/terminal/warp_drive_nav2.png) + +## Import and Export + +Every object in Warp Drive can be exported to or imported from a file. When importing or exporting, objects are converted as follows: + +* [Workflows](/knowledge-and-collaboration/warp-drive/workflows/) import from and export to YAML (.yaml, .yml) +* [Prompts](/knowledge-and-collaboration/warp-drive/prompts/) import isn't supported at this time, but you can export to YAML (.yaml, .yml) +* [Notebooks](/knowledge-and-collaboration/warp-drive/notebooks/) import from and export to MARKDOWN (.md) +* [Environment Variables](/knowledge-and-collaboration/warp-drive/environment-variables/) import isn't supported at this time, but you can export to DOTENV (.env) + +### Importing files into Warp Drive + +To import a local file or directory, `RIGHT-CLICK` on a folder or click **+** on a workspace and choose "Import." If importing a directory, supported files in the directory and its sub-directories will be imported into a matching folder structure. + +![Import modal](../../../../assets/terminal/notebook-import-modal.png) + +### Exporting files from Warp Drive + +To export a single Warp Drive object, `RIGHT-CLICK` on an object and choose "Export" from the menu, then select a directory for export. To export all Warp Drive objects, Open the [Command Palette](/terminal/command-palette/#how-to-access-it), search for and select "Export all Warp Drive objects", then select a directory for export. + +## Sharing your drive objects + +Every object in Warp Drive can be shared. There are three ways to share objects: + +* **Teams:** All members of a Warp team have full access to the objects in its Drive. +* **Direct Sharing:** Objects can be shared directly with individuals by email. +* **Link-based Sharing:** You can make an object public to anyone with the link, including those without Warp accounts. + +### Sharing a drive object using links + +To share a Drive object, navigate to the object's overflow menu, and choose "Copy link". Once the link is successfully copied to your clipboard, you can share it with teammates and reference your object in your codebase, documentation, or communication channels like Slack. + +:::note +To access an object, link-followers must have permission to open it through one of the sharing methods above. If they do not have permission, they can automatically request access from the object owner or team admin. +::: + +![Copy link Menu Item](../../../../assets/terminal/wd-copy-link-menu.png) + +### Managing permissions + +To manage a Drive object's permissions, navigate to its overflow menu and choose "Share". If the object is open, you can also use the [Command Palette](/terminal/command-palette/#how-to-access-it) and search for "Share pane", or click the share button in the pane header: + +![The pane header for a notebook, with the share button circled](../../../../assets/terminal/wd-share-button.png) + +This opens a dialog that lists the current sharing settings and allows you to change them: + +![A sharing dialog showing that anyone with the link can view, the owner has full access, and another user can edit.](../../../../assets/terminal/wd-share-dialog.png) + +In this dialog, you can: + +* Invite other users directly using the email input at the top. +* Change or remove the public link-based access level. +* Update the access level for individual users, or remove their access. + +Permissions are inherited from parent folders. For example, if a folder was shared with edit permissions, then the user would also be able to edit all objects inside the folder or its subfolders. + +Owners and their teammates always have full access. When sharing an object, you can choose between view and edit access. + +| | Can view | Can edit | Full access | +| ----------------------------------- | -------- | -------- | ----------- | +| Read a notebook | ✓ | ✓ | ✓ | +| Execute a Workflow | ✓ | ✓ | ✓ | +| Use env vars | ✓ | ✓ | ✓ | +| Edit contents | | ✓ | ✓ | +| Create objects in a folder | | ✓ | ✓ | +| Trash or untrash | | ✓ | ✓ | +| Delete permanently | | | ✓ | +| Modify permissions | | | ✓ | +| Move to a different folder or drive | | | ✓ | + +## Troubleshooting Warp Drive + +* If you were previously using Warp on your own and were later invited to join a team, you may need to exit, update, and restart the Warp app to gain access to your team’s shared drive and commands +* Navigating to Settings > Teams in Warp should also force a metadata update for you, which will ensure you have access to the latest versions of Workflows in your team's drive diff --git a/src/content/docs/knowledge-and-collaboration/warp-drive/notebooks.mdx b/src/content/docs/knowledge-and-collaboration/warp-drive/notebooks.mdx new file mode 100644 index 0000000..4dd741c --- /dev/null +++ b/src/content/docs/knowledge-and-collaboration/warp-drive/notebooks.mdx @@ -0,0 +1,151 @@ +--- +title: Warp Drive Notebooks +description: >- + Save interactive playbooks to simplify onboarding and development. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +### What is a Notebook? + +Notebooks are runnable documentation consisting of markdown text and list elements, code blocks, and runnable shell snippets that can be automatically executed in your terminal session. Notebooks are searchable and accessible through the [Command Palette](/terminal/command-palette/) so you can access and run your documentation without ever leaving the terminal. You can also export Notebooks in .md format at any time. + +### How to save and edit notebooks + +You can create a new notebook from various entry points in Warp + +<Tabs> + <TabItem label="macOS"> + * From Warp Drive, + > New notebook + * From the [Command Palette](/terminal/command-palette/), create a new team or personal notebook. + </TabItem> + <TabItem label="Windows"> + * From Warp Drive, + > New notebook + * From the [Command Palette](/terminal/command-palette/), create a new team or personal notebook. + </TabItem> + <TabItem label="Linux"> + * From Warp Drive, + > New notebook + * From the [Command Palette](/terminal/command-palette/), create a new team or personal notebook. + </TabItem> +</Tabs> + +Any of these entry points will open the notebook editor where you can: + +* Title your notebook. +* Start adding text and code elements. + +:::note +Note: The notebook will not be saved until either title or body text is added. +::: + +![Editing a Notebook](/assets/terminal/notebooks_editor.gif) + +### Working with Notebooks + +#### Adding new elements + +Notebook elements (text, code, list items) can be added in several ways: + +* Using the appropriate markdown shortcut (e.g. ### for Heading 3). +* Typing /, which will open up a selection menu of supported elements. +* Pressing the + icon which appears when hovering over a line and selecting from the menu of supported elements. + +![Markdown element types](../../../../assets/terminal/markdown-element-types.png) + +#### Styling existing elements + +Existing notebook elements can be styled in several ways: + +* Selecting an existing element and selecting text decorations (like bold, italics, or inline code) from the hover menu. +* Using markdown syntax for text stylings like \*\*bold\*\* or \*italic\*. +* Selecting an existing element and changing the overall type of the element via the dropdown element menu. + +<div data-full-width="true">![Styling menu](../../../../assets/terminal/styling-menu.png)</div> + +#### Using Command and Code Blocks + +Command and code blocks have several unique properties such as syntax highlighting and quick actions that make working with code-based documentation simple. You can create a code or command block by either: + +* Selecting Command or Code from the new element menu +* Typing ` ``` ` (triple backticks) + +Once you’ve inserted your code block you can select the language at the bottom of the block from numerous options which will apply the appropriate syntax highlighting if available (or default to Code if your language is not found). All code and command blocks will apply syntax highlighting and provide a quick copy button for easy access. + +![Example code block](../../../../assets/terminal/notebook-code-block.png) + +#### Special properties of command blocks + +If you insert a Command block or specify the language as “Shell”, Warp provides extra functionality to simplify terminal work. + +#### Executing Command Blocks + +Developers can execute shell command blocks by: + +<Tabs> + <TabItem label="macOS"> + * Using the insert button at the bottom of the block + * Pressing `CMD-ENTER` while the block is selected (a blue highlight will appear) + </TabItem> + <TabItem label="Windows"> + * Using the insert button at the bottom of the block + * Pressing `CTRL-ENTER` while the block is selected (a blue highlight will appear) + </TabItem> + <TabItem label="Linux"> + * Using the insert button at the bottom of the block + * Pressing `CTRL-ENTER` while the block is selected (a blue highlight will appear) + </TabItem> +</Tabs> + +The command text will be inserted into the developer’s active terminal session, or a new session if none are active. + +![Run option for command block](../../../../assets/terminal/notebook-cmd-block-run.png) + +#### Adding arguments to Command Blocks + +Command blocks accept parameters in the same format as [Workflows](/knowledge-and-collaboration/warp-drive/workflows/). To add an argument to your command block, use `{{double_curly_brackets}}` to specify your argument term. + +![Command block with parameters](../../../../assets/terminal/notebook-cmd-with-params.png) + +#### Navigating command blocks with the keyboard + +Command Blocks also support keyboard navigation. There are two ways to enter the keyboard navigation mode: + +<Tabs> + <TabItem label="macOS"> + * Clicking on a shell block. + * Pressing `CMD-UP` or `CMD-DOWN.` + + Once a command block is selected, press `CMD-ENTER` to insert it into the terminal input. You can also use `UP, DOWN, CMD-UP`, and `CMD-DOWN` to navigate between command blocks. While the Notebook is focused, press `CMD-L` to switch focus back to the terminal without inserting a command. + </TabItem> + <TabItem label="Windows"> + * Clicking on a shell block. + * Pressing `CTRL-UP` or `CTRL-DOWN.` + + Once a command block is selected, press `CTRL-ENTER` to insert it into the terminal input. You can also use `UP, DOWN, CTRL-UP,` and `CTRL-DOWN` to navigate between command blocks. While the Notebook is focused, press `CTRL-L` to switch focus back to the terminal without inserting a command. + </TabItem> + <TabItem label="Linux"> + * Clicking on a shell block. + * Pressing `CTRL-UP` or `CTRL-DOWN.` + + Once a command block is selected, press `CTRL-ENTER` to insert it into the terminal input. You can also use `UP, DOWN, CTRL-UP,` and `CTRL-DOWN` to navigate between command blocks. While the Notebook is focused, press `CTRL-L` to switch focus back to the terminal without inserting a command. + </TabItem> +</Tabs> + +#### Adding existing Workflows to notebooks + +If you have existing [Workflows](/knowledge-and-collaboration/warp-drive/workflows/) that you’d like to insert into your notebook rather than duplicating their content, you can select Embedded Workflow from the new element menu and select from the available Workflows. Once embedded in a notebook, the workflow will be executable like a regular command block. To edit the content of the embedded workflow, you will need to edit the source workflow which can be found by searching for the title in the [Command Palette](/terminal/command-palette/). + +![Embedding an existing workflow in a notebook.](../../../../assets/terminal/embedding-a-workflow.png) + +### Working with Notebooks in a team + +If the notebook is shared with a team, all team members will have access to edit the notebook and updates will sync immediately for all members of the team. + +:::note +Note that only one editor is allowed at a given time. Opening the notebook while there is an active editor will open the notebook in Viewing mode. Your mode (view vs edit) can be toggled above the notebook’s title. +::: + +![View mode example](../../../../assets/terminal/notebook-view-mode.png) + +### Import and export notebooks in Warp Drive + +Please see our [Warp Drive Import and Export](/knowledge-and-collaboration/warp-drive/#import-and-export) instructions. diff --git a/src/content/docs/knowledge-and-collaboration/warp-drive/prompts.mdx b/src/content/docs/knowledge-and-collaboration/warp-drive/prompts.mdx new file mode 100644 index 0000000..be4239a --- /dev/null +++ b/src/content/docs/knowledge-and-collaboration/warp-drive/prompts.mdx @@ -0,0 +1,78 @@ +--- +title: Warp Drive prompts +description: >- + Save and reuse parameterized Agent Mode prompts to run on-demand. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +## What is a prompt? + +A prompt is a parameterized natural language query you can name and save in Warp to use with [Agent Mode](/agent-platform/local-agents/interacting-with-agents/). + +Prompts are searchable and easily accessed from the [Command Palette](/terminal/command-palette/) so you can find and execute them without switching context. They allow you to save and reuse specific and complex AI workflows, making it easier to repeat multi-step tasks with Agent Mode. + +![View of a Prompt in Warp Drive showing the command view interface](../../../../assets/terminal/prompts-command-view.png) + +### Demo: Trigger reusable actions with saved prompts + +Here's an example from [Warp Guides](/guides/), where Zach walks through what prompts he uses for PRs and Git commits: + +<VideoEmbed url="https://www.youtube.com/watch?ab_channel=Warp&v=pE15zjJmB4E" /> + +There are other great examples of prompts on [Do Things](https://dothings.warp.dev/) and [Warp Guides](/guides/). + +## How to save and edit prompts + +You can create a new prompt from Warp Drive by clicking the + button and selecting "Prompt". + +* Name your prompt +* Edit the natural language query along with any arguments (also known as parameters) +* Add a meaningful description that will be indexed for search (optional) +* Add arguments, descriptions for arguments, and default values (optional) + +![View of the Prompt editor interface showing the edit form with fields for name, query, description, and arguments](../../../../assets/terminal/prompts-edit-view.png) + +Once a prompt has been created, you can edit it at any time, as long as you have access to an internet connection. + +### Working with arguments + +In the prompt editor, you can add arguments manually with "New argument" or by typing in double curly braces (`{{argument}}`) within the command field. If you select "New argument" while you have text selected, Warp will wrap that text in curly braces to create an argument. + +There are some rules for creating valid arguments: + +* Argument names can only include characters `A-Za-z0-9`, hyphens `-` and underscores `_` +* The first character of an argument cannot be a number + +Arguments can be one of two types: text or enum. By default, all new arguments are text type. + +#### Enum type arguments + +Enums allow you to specify expected inputs to a prompt argument. When you insert a prompt with enums into the input editor, you will be prompted with suggestions for filling in the argument. You can open the suggestions menu by pressing `SHIFT-TAB` while selecting an argument. + +For detailed information about creating and using enum type arguments, please see the [Enum type arguments section in Workflows documentation](/knowledge-and-collaboration/warp-drive/workflows/#enum-type-arguments). + +### Editing prompts with a team + +If the prompt is shared with a team, all team members will have access to edit it and updates will sync immediately for all members of the team. + +If a prompt in the Warp Drive has been edited by another team member or a user on another device while you are attempting to edit the same prompt, you will not be able to save changes; you will need to check out the latest version and try again. + +## How to execute prompts + +You can execute a prompt in several ways: + +* From Warp Drive, click the prompt +* From the [Command Palette](/terminal/command-palette/) or [Command Search](/terminal/entry/command-search/), search for a prompt by name or type "prompts:" to see all available prompts and your prompt history +* When a prompt is selected, you can use `SHIFT-TAB` to cycle through the arguments. + +![Command Palette interface showing a search for Prompts with results displayed](../../../../assets/terminal/prompts-command-palette.png) + +![Command Search interface showing a search for Prompts with results displayed](../../../../assets/terminal/prompts-command-search.png) + +These options will paste the prompt into your active terminal input. Prompt names and any relevant descriptions and arguments will be displayed in a dialog, so you can understand how to use the prompt. + +You can make any adjustments you need to the arguments before running the prompt in your input editor. + +### Import and export prompts in Warp Drive + +Please see our [Warp Drive Import and Export](/knowledge-and-collaboration/warp-drive/#import-and-export) instructions. diff --git a/src/content/docs/knowledge-and-collaboration/warp-drive/web.mdx b/src/content/docs/knowledge-and-collaboration/warp-drive/web.mdx new file mode 100644 index 0000000..a4cc707 --- /dev/null +++ b/src/content/docs/knowledge-and-collaboration/warp-drive/web.mdx @@ -0,0 +1,84 @@ +--- +title: Warp Drive on the web +description: >- + Access your Warp Drive objects and shared sessions from any browser or touch + screen device, including mobile phones, tablets, and touch-enabled laptops. +--- + +## What is Warp on the web? + +Warp Drive on the Web lets you view and edit your Warp Drive objects and shared sessions directly in the browser, on any device. + +![A web-based rendering of a Team Workflow](../../../../assets/terminal/wd-web-team-workflow.png) + +## How to access Warp on the web + +Warp's web-based viewing experience can currently be accessed via: + +* The [`app.warp.dev/app` homepage](https://app.warp.dev/app) +* [Drive Object](/knowledge-and-collaboration/warp-drive/#sharing-your-drive-objects) Links +* [Session Sharing](/knowledge-and-collaboration/session-sharing/#how-to-allow-access-to-collaborators-in-your-session) Links + +:::caution +You can edit and view web-based objects and sessions as normal. The one exception is executing a command from a workflow or notebook since there is no shell session running on the web. +::: + +## Managing your view preferences - web or desktop + +If the Warp app is installed, links will open on the desktop by default. You can manage whether Warp links open in Warp's desktop app or the browser in multiple ways: + +:::note +The desktop option is only presented if Warp's web service is able to detect the Warp app installed locally. Warp desktop opens localhost port 9277 to accomplish this detection. This is done in a separate process that does not have access to your terminal contents.\ +\ +If you would like to use Warp locally and do not have it installed, please visit our [installation guide.](/getting-started/quickstart/installation-and-setup/) +::: + +1. The first time you follow a link, if Warp is not installed, you will be prompted to download it. You can dismiss the popup to stay on the web. + +![Popup prompting to download Warp Desktop when viewing a Drive object on the web](../../../../assets/terminal/wd-popup-message.png) + +2. This preference can be changed at any point in **Settings** > **Features** > **General** > **Open links in desktop app** Note that this setting is only available while on the web-based version of Warp. + + ![Setting managing how to open links](../../../../assets/terminal/wd-open-links-preference.png) +3. You can always switch between web and desktop views on a case-by-case basis. + 1. To switch from a web-view to Desktop for a given object, open the _overflow menu > Open link on Desktop._ + + ![Overflow menu on a web-based Drive object with the Open on Desktop option highlighted](../../../../assets/terminal/wd-switch-viewer.png) + 2. To stay on the web for a given object despite a global Desktop preference, follow the _View on the web_ option that is part of the redirect screen to Desktop. + + ![Redirect screen with Open Warp and View on the web options](../../../../assets/terminal/wd-view-on-web.png) + +## Supported Browsers + +Warp on the web supports all modern browsers, including: + +**Desktop** + +* Chrome +* Firefox +* Safari + +**Mobile** + +* iOS Safari 15+ +* Android Chrome 58+ +* Samsung Internet 7.2+ + +:::note +These mobile browser versions are the minimum required for WebGL 2.0 support. Most up-to-date devices meet these requirements. +::: + +## Touch screen and mobile support + +Warp supports all touch screen devices, including mobile phones, tablets, and touch-enabled laptops. Touch input works on both the web and the desktop app. + +### Supported gestures + +* **Touch and scroll** - Vertical and horizontal scrolling work as expected +* **Double tap** - Select text or elements +* **Long press (hold)** - Open context menu (equivalent to right-click) + +## Related features + +* [Warp Drive](/knowledge-and-collaboration/warp-drive/) - Store and share workflows, prompts, and environment variables +* [Session Sharing](/knowledge-and-collaboration/session-sharing/) - Collaborate with others in real-time terminal sessions diff --git a/src/content/docs/knowledge-and-collaboration/warp-drive/workflows.mdx b/src/content/docs/knowledge-and-collaboration/warp-drive/workflows.mdx new file mode 100644 index 0000000..eeb6baf --- /dev/null +++ b/src/content/docs/knowledge-and-collaboration/warp-drive/workflows.mdx @@ -0,0 +1,122 @@ +--- +title: Warp Drive Workflows +description: >- + Save parameterized commands as Workflows and execute them on-demand from + Warp Drive. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +## What is a workflow? + +A workflow is a parameterized command you can name and save in Warp with descriptions and arguments. Workflows are searchable and easily accessed from the [Command Palette](/terminal/command-palette/) so you can find and execute them without switching contexts. + +## How to save and edit workflows + +You can create a new workflow from various entry points in Warp: + +* From Warp Drive, + > New workflow +* Using Block Actions, Save as Workflow +* From Oz agent results, Save as Workflow +* From the [Command Palette](/terminal/command-palette/), Create a New Personal Workflow + +Any of these entry points will open the workflow editor where you can: + +* Name your workflow +* Edit the command along with any arguments (also known as parameters) +* Add a meaningful description that will be indexed for search (optional) +* Add arguments, descriptions for arguments, and default values (optional) + +![Workflows save and edit modal](../../../../assets/terminal/edit-workflow-pane.png) + +<VideoEmbed url="https://www.youtube.com/watch?v=8UmreUTTrkg&start=9s&end=198s" title="Save Workflow Demo" /> + +### Working with arguments + +In the workflow editor, you can add arguments manually with "New argument" or by typing in double curly braces (`{{argument}}`) within the command field. If you select "New argument" while you have text selected, Warp will wrap that text in curly braces to create an argument. + +There are some rules for creating valid arguments: + +* Argument names can only include characters `A-Za-z0-9`, hyphens `-` and underscores `_` +* The first character of an argument cannot be a number + +Arguments can be one of two types: text or enum. By default, all new arguments are text type. + +#### Enum type arguments + +Enums allow you to specify expected inputs to a workflow argument. When you insert a workflow with enums into the input editor, you will be prompted with suggestions for filling in the argument. You can open the suggestions menu by pressing `SHIFT-TAB` while selecting an argument. + +<VideoEmbed url="https://www.loom.com/share/b2f54eeef2f247a8bbcf87698b2a4287?hideEmbedTopBar=true&hide_owner=true&hide_share=true&hide_title=true" title="Enum Input Suggestions Demo" /> + +To create an enum type argument: + +1. Navigate to the "default value" field of an argument. +2. Select the "Enum" type. +3. Click "New" to create a new enum, or select an existing one from the dropdown menu. +4. If you selected "New", you can choose to create a "Static" enum or "Dynamic" enum. Dynamic enums are associated with a shell command whose output is parsed to determine the set of valid values for that argument. + +<VideoEmbed url="https://www.loom.com/share/b429ab7f7014418e9591e505fd71af83?hideEmbedTopBar=true&hide_owner=true&hide_share=true&hide_title=true" title="Enum Creation Demo" /> + +### Working with aliases + +Workflow aliases allow you to create personalized shortcuts and custom configurations for your frequently used workflows. These aliases provide enhanced flexibility in how you use and configure workflows. Aliases are personal to your account, not shared with everyone who has the workflow. If settings sync is enabled, they'll be synced across devices logged in to your account. Aliases can set default values for each [argument](/knowledge-and-collaboration/warp-drive/workflows/#working-with-arguments), but don't have to. Aliases can have [Environmental Variables](/knowledge-and-collaboration/warp-drive/environment-variables/) associated with them. + +:::note +Workflow aliases are not compatible with [YAML Workflows](/terminal/entry/yaml-workflows/). They can only be used with Workflows created in [Warp Drive](/knowledge-and-collaboration/warp-drive/). +::: + +### Editing workflows + +Once a workflow has been created, you can edit it at any time, as long as you have access to an internet connection. + +![Edit workflow menu](../../../../assets/terminal/Edit_Workflow.png) + +#### AI Autofill + +Workflows also have the option to use an [Oz agent](/agent-platform/local-agents/overview/) to automatically generate a title, descriptions, or parameters. + +* Create or edit a Workflow, in the edit view you should see the option to AutoFill. +* Warp will fill in the fields based on the Workflow you're creating. + +<DemoVideo src="/assets/terminal/Edit-workflows-autofill.mp4" label="Edit Workflows - Autofill" /> + +### Editing workflows with a team + +If the workflow is shared with a team, all team members will have access to edit the workflow and updates will sync immediately for all members of the team. + +If a workflow in the Warp Drive has been edited by another team member or a user on another device while you are attempting to edit the same workflow, you will not be able to save changes; you will need to check out the latest version and try again. + +## How to execute workflows + +You can execute a workflow in several ways: + +* From Warp Drive, click the workflow +* From the [Command Palette](/terminal/command-palette/), search for a workflow you’d like to execute, click or select, and enter +* From [Command Search](/terminal/entry/command-search/), search for a workflow you'd like to execute, click or select, and enter. +* When a workflow is selected, you can use `SHIFT-TAB` to cycle through the arguments. + +:::note +When you create two or more arguments with the same name, Warp automatically selects and puts multiple cursors over the arguments in the input editor so they are synced.\ +\ +Also, tailor your Command Search experience by toggling off "Show Global Workflows" in **Settings** > **Features**. When disabled, your search will exclusively encompass YAML and Warp Drive Workflows. +::: + +![Search for any workflow in the Command Palette with CMD + P](../../../../assets/terminal/search-workflow-command-palette.png) + +These options will paste the workflow into your active terminal input. Workflow names and any relevant descriptions and arguments will be displayed in a dialog, so you can understand how to use the workflow. + +![Execute a Workflow](../../../../assets/terminal/execute-a-workflow.png) + +You make any adjustments you need to the arguments (or the command itself) before running the command in your input editor. + +<VideoEmbed url="https://www.youtube.com/watch?v=8UmreUTTrkg&start=344s&end=370s" title="Running Workflow Demo" /> + +## Support for YAML Workflows + +Warp will indefinitely support the [YAML Workflows](/terminal/entry/yaml-workflows/), which includes personal and community workflows sourced from an open-source repository. + +If needed, you can continue to access your `.yaml` file workflows using [Command Search](/terminal/entry/command-search/) or the [Command Palette](/terminal/command-palette/). However, these file-based workflows will not be available to access, organize, or share in Warp Drive. + +### Import and export workflows in Warp Drive + +Please see our [Warp Drive Import and Export](/knowledge-and-collaboration/warp-drive/#import-and-export) instructions. diff --git a/src/content/docs/quickstart.mdx b/src/content/docs/quickstart.mdx new file mode 100644 index 0000000..9275556 --- /dev/null +++ b/src/content/docs/quickstart.mdx @@ -0,0 +1,120 @@ +--- +title: Warp quickstart +description: >- + Get up and running with Warp in about 10 minutes. Install, run your first + commands, talk to an agent, and discover what makes Warp different. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +This guide walks you through installing Warp, trying the terminal features you'll use every day, and firing off your first agent prompt. After completing the steps in this guide, you'll have a working Warp setup and a clear picture of how terminal commands and agents work together. + +--- + +## Prerequisites + +* **macOS, Windows, or Linux** - See [Installation and setup](/getting-started/quickstart/installation-and-setup/) for minimum requirements per platform. + +--- + +## 1. Install Warp + +Download Warp from [warp.dev](https://www.warp.dev/download) and follow the installer for your platform. + +<Tabs> + <TabItem label="macOS"> + Download and drag Warp into your Applications folder, or install with Homebrew: + + ```bash + brew install --cask warp + ``` + </TabItem> + <TabItem label="Windows"> + Download and run the installer, or install with WinGet: + + ```powershell + winget install Warp.Warp + ``` + </TabItem> + <TabItem label="Linux"> + Download the package for your distribution from [warp.dev/download](https://www.warp.dev/download). For Debian/Ubuntu: + + ```bash + sudo apt install ./warp-terminal.deb + ``` + + See [Installation and setup](/getting-started/quickstart/installation-and-setup/) for all Linux options. + </TabItem> +</Tabs> + +When you launch Warp, you'll see a terminal session ready for input. You can optionally sign up for an account (top right), or skip and start using Warp immediately. + +## 2. Run a command and see Blocks + +Run any command you'd normally use, for example: + +```bash +ls -la +``` + +You'll notice the output looks different from a traditional terminal. Every command and its output is grouped into a **Block** — a contained unit you can copy, search, filter, and navigate independently. Blocks are the foundation of how Warp organizes your terminal. + +**What you can do with Blocks:** + +* Click a Block to select it, then press `⌘C` (macOS) or `Ctrl+Shift+C` (Windows/Linux) to copy the output +* Use `⌘↑`/`⌘↓` (macOS) or `Ctrl+↑`/`Ctrl+↓` (Windows/Linux) to navigate between Blocks +* Click the filter icon on a Block to search within its output + +Learn more about navigating, selecting, and acting on output in [Block basics](/terminal/blocks/block-basics/). + +## 3. Try the input editor + +Warp's input isn't a standard terminal prompt, it's a real text editor. Try the following functionality: + +* **Multi-line editing** - Press `Shift+Enter` to add a new line. Try typing three separate `echo` lines, pressing `Shift+Enter` between each, then `Enter` to run them all at once. +* **Click to place your cursor** - Click anywhere in your input to move the cursor, just like a text editor. +* **Select and edit** - Click and drag to select text, then type to replace it. + +All three commands run in sequence, and each produces its own Block. No need to run commands one at a time. + +Learn more about cursor movement, selections, and multi-line input in [Modern text editing](/terminal/editor/). + +## 4. See autosuggestions and completions + +Start typing a command you've run before. You'll see a faded suggestion appear inline based on your shell history. Press `→` to accept it instantly. + +Press `Tab` while typing to see completions for commands, flags, and file paths. Warp provides enhanced completions beyond what your shell offers natively. + +If you mistype a command, Warp detects the error and suggests a correction. Accept the fix or dismiss it and continue. + +Learn more about [Autosuggestions](/terminal/command-completions/autosuggestions/) and [Tab completions](/terminal/command-completions/completions/). + +## 5. Ask your first agent question + +Everything you've done so far has been in **terminal mode**, running shell commands the way you normally would. Warp also has **Agent Mode**, a dedicated conversation view where you interact with Oz, Warp's built-in agent, using natural language. + +Start an agent conversation by pressing `⌘↩` (macOS) or `Ctrl+Shift+Enter` (Windows/Linux). Then type a prompt: + +``` +Explain the architecture of this project +``` + +Oz reads your codebase, understands its structure, and responds with a context-aware explanation. From here you can ask follow-up questions, have Oz write or refactor code, debug errors, or run commands on your behalf — all within the same conversation. + +:::note +You don't always need to switch modes manually. If you type a natural-language prompt in terminal mode, Warp auto-detects it and offers to send it to an agent. +::: + +Warp also works with third-party CLI agents like Claude Code and Codex. Learn more about [third-party CLI agents](/agent-platform/cli-agents/overview/). + +To learn more about switching between modes, see [Terminal and Agent modes](/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes/). + +--- + +## What to explore next + +Now that you have the basics, check out the features that make Warp a full development environment: + +* **[Customizing Warp](/getting-started/quickstart/customizing-warp/)** — Pick a theme, configure your prompt, choose your AI model, and import keybindings from another terminal. +* **[Codebase Context](/agent-platform/capabilities/codebase-context/)** — Index your Git repositories so agents understand your code and give context-aware answers across large, multi-repo systems. +* **[Oz cloud agents](/agent-platform/cloud-agents/overview/)** — Run agents in the background for PR review, issue triage, dependency updates, and other tasks that don't need your immediate attention. +* **[Keyboard shortcuts](/getting-started/keyboard-shortcuts/)** — The full shortcut reference for power users. diff --git a/src/content/docs/reference/api-and-sdk/demo-sentry-monitoring-with-sdk.mdx b/src/content/docs/reference/api-and-sdk/demo-sentry-monitoring-with-sdk.mdx new file mode 100644 index 0000000..776b2da --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/demo-sentry-monitoring-with-sdk.mdx @@ -0,0 +1,27 @@ +--- +title: "Demo: Sentry monitoring with SDK" +description: >- + Build a Sentry webhook handler that triggers Oz agents to investigate errors + and create draft PRs. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +### Turn Production Errors into Draft PRs with Cloud Agents + TypeScript SDK + +<VideoEmbed url="https://www.youtube.com/watch?feature=youtu.be&v=fHQXLg9ybi4" /> + +:::note +Example repository: [**https://github.com/warpdotdev/warp-agents-sdk-demo-sentry-monitor**](https://github.com/warpdotdev/warp-agents-sdk-demo-sentry-monitor) +::: + +In this demo, Ben builds a small TypeScript “Sentry monitor” service that listens for specific Sentry alerts (like a Go nil pointer dereference) and triggers a Warp cloud agent to investigate. The server validates the webhook, extracts the stack trace, and injects it into an agent run inside a Warp Environment so the agent can inspect the repo and propose a fix. + +He also covers the task lifecycle basics in the TypeScript SDK (running an agent, polling task state to fetch a session link for debugging), and shows the end result: a draft GitHub pull request created from the Sentry event for a maintainer to review. + +**What Ben covers** + +* Using Warp's TypeScript SDK to trigger agent runs and retrieve run details. +* Handling run lifecycle states (queued → running) to reliably fetch a session link. +* Running agents inside a Warp Environment so they can investigate real code, run tests, and validate fixes. +* Building a lightweight Sentry webhook server that filters, validates, and routes only the right errors to an agent. +* Creating a workflow that results in draft PRs for human review, instead of silent autonomous changes. diff --git a/src/content/docs/reference/api-and-sdk/index.mdx b/src/content/docs/reference/api-and-sdk/index.mdx new file mode 100644 index 0000000..4bd3669 --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/index.mdx @@ -0,0 +1,147 @@ +--- +title: "Oz API & SDK" +description: >- + Create and inspect cloud agent runs over HTTP with the Oz API, or use the + Python and TypeScript SDKs for typed requests, retries, and error handling. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +### Oz API + +The Oz API lets you create and inspect [Cloud Agent](/agent-platform/cloud-agents/overview/) runs over HTTP from any system (CI, cron, backend services, internal tools), without requiring the Warp desktop app. + +**With the API you can:** + +* Run an agent by submitting a prompt plus optional config (model, environment, MCP servers, base prompt, etc.) +* Monitor execution by listing runs and tracking state transitions over time (queued → in progress → succeeded/failed) +* Inspect results and provenance by fetching a run's full details, including the original prompt, source/creator metadata, session link, and resolved agent configuration + +:::caution +This page is a high-level overview.\ +\ +For full API endpoint details, please refer to the [**Agents API Reference**](/api)**.** For schema definitions, see the SDK repos: [**Python SDK**](https://github.com/warpdotdev/oz-sdk-python) and [**TypeScript SDK**](https://github.com/warpdotdev/oz-sdk-typescript). +::: + +### Oz Agent SDK + +Oz provides official [Python](https://github.com/warpdotdev/oz-sdk-python) and [TypeScript](https://github.com/warpdotdev/oz-sdk-typescript) SDKs that wrap the Oz API with: + +* **Typed requests and responses** (editor autocomplete, fewer schema mistakes) +* **Built-in retries and timeouts** (with per-request overrides) +* **Consistent error type**s that map to API status codes +* **Helpers for raw responses** when you need headers/status or custom parsing + +If you’re building an integration (CI, Slack bots, internal tooling, orchestrators), the SDKs are typically the quickest and safest starting point. + +<VideoEmbed url="https://www.youtube.com/watch?v=0cf7383MZSk" /> + +**SDK vs raw REST** + +* Use the SDK when you want strong typing, standardized error handling, and easy concurrency patterns. +* Use raw REST when you want minimal dependencies or full control over your HTTP client (the SDKs also support calling undocumented endpoints when needed). + +:::caution +For the full SDK surface area and latest usage, refer to the GitHub repos: [**Python SDK**](https://github.com/warpdotdev/oz-sdk-python) and [**TypeScript SDK**](https://github.com/warpdotdev/oz-sdk-typescript). +::: + +--- + +## Oz API + +### REST API Base URL + +All endpoints are served over HTTPS: + +```http +https://app.warp.dev/api/v1 +``` + +### Core Concepts + +#### **Agent runs** + +An agent run represents a single execution of a cloud agent, created with a prompt and optional configuration. Each run has: + +* A unique `run_id` +* A human-readable `title` +* A `prompt` that the agent executes +* A `state` (for example `QUEUED`, `INPROGRESS`, `SUCCEEDED`, `FAILED`) +* Timestamps (`created_at`, `updated_at`) +* Optional session information (`session_id`, `session_link`) +* Optional resolved configuration (`agent_config`) + +See the [**Agents API Reference**](/api) for details on how runs are created and listed. + +#### **Agent configuration** + +You can influence how an agent runs using AmbientAgentConfig, including: + +* `name` — a human-readable label for grouping, filtering, and traceability. When you run an agent from a [skill](/agent-platform/capabilities/skills/), `name` is automatically set to the skill name. You can also set `name` explicitly via the API, SDK, or CLI (`--name`) to categorize runs by intent — for example, grouping all runs of a particular workflow regardless of how they were triggered. Use the `name` query parameter on `GET /agent/runs` to filter runs by config name. +* `model_id` for LLM selection +* `base_prompt` to shape behavior +* `environment_id` to choose a `CloudEnvironment` +* `skill_spec` to use a [skill](/agent-platform/capabilities/skills/) as the base prompt (format: `owner/repo:skill-name` or `owner/repo:path/to/SKILL.md`) +* `mcp_servers` to enable specific tools via MCP + +See the [**Python SDK**](https://github.com/warpdotdev/oz-sdk-python) or [**TypeScript SDK**](https://github.com/warpdotdev/oz-sdk-typescript) for the full configuration schema. + +--- + +### Key Endpoints + +**The Agents API exposes three primary endpoints:** + +* `POST /agent/run` + + Create a new agent run with a prompt and optional config and title. Returns run\_id and initial state. +* `GET /agent/runs` + + List runs with pagination and filters for state, config\_name, model\_id, creator, source, and creation time. +* `GET /agent/runs/{runId}` + + Fetch full details for a single run, including session link and resolved configuration. + +All endpoint semantics, query parameters, and error codes are documented on the [Agents API Reference](/api). + +--- + +#### Models Reference + +The API shares a set of reusable models across endpoints. Detailed JSON schemas, types, and enums are available in the SDK repos ([Python](https://github.com/warpdotdev/oz-sdk-python), [TypeScript](https://github.com/warpdotdev/oz-sdk-typescript)). Key models include: + +* `RunAgentRequest` +* `RunAgentResponse` +* `ListRunsResponse` +* `RunItem` +* `PageInfo` +* `RunStatusMessage` +* `RunCreatorInfo` +* `RunState` +* `RunSourceType` +* `AmbientAgentConfig` +* `MCPServerConfig` +* `Error` + +--- + +## Oz Agent SDKs + +### Python SDK + +The Python SDK is the recommended way to call the Oz API from Python services and scripts. It provides: + +* Sync + async clients +* Typed request/response models +* Configurable retries/timeouts and structured errors + +See the [**Python SDK GitHub repo**](https://github.com/warpdotdev/oz-sdk-python) for installation, full API reference (api.md), and up-to-date examples. + +### TypeScript SDK + +The TypeScript SDK is the recommended way to call the Oz API from Node.js services and modern TS/JS runtimes. It provides: + +* Fully typed params/responses +* First-class error handling, retries/timeouts +* Support across common runtimes where fetch is available or polyfilled + +See the [**TypeScript SDK GitHub repo**](https://github.com/warpdotdev/oz-sdk-typescript) for installation, full API reference (api.md), and up-to-date examples. diff --git a/src/content/docs/reference/api-and-sdk/quickstart.mdx b/src/content/docs/reference/api-and-sdk/quickstart.mdx new file mode 100644 index 0000000..3204a12 --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/quickstart.mdx @@ -0,0 +1,95 @@ +--- +title: "API & SDK quickstart" +description: >- + Create and monitor your first cloud agent run via the Oz API or SDK in ~5 + minutes. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +The Oz API lets you run and manage cloud agents from anywhere — CI/CD pipelines, backend services, scripts, or custom tooling — without the Warp desktop app. This quickstart walks you through creating your first run and checking its status. + +Watch this short demo of how the REST API can power agent-backed apps like [PowerFixer](https://github.com/warpdotdev/power-fixer-setup), an issue triage bot built by the Warp team: +<VideoEmbed url="https://youtu.be/N6qMe641K34" /> + +--- + +## Prerequisites + +* **A Warp API key** - In the Warp app, click your profile photo, then go to **Settings** > **Cloud platform** > **Oz Cloud API Keys** to create a key and copy the raw value. See [API Keys](/reference/cli/api-keys/) for step-by-step instructions. +* **An Oz cloud environment** - Agents run inside a configured environment that includes repos and other dependencies. If you don't have an environment yet, follow the [Cloud Agents Quickstart](/agent-platform/cloud-agents/quickstart/) first. + +--- + +## 1. Set your API key + +Export your API key so the API can authenticate your requests automatically — all commands in this guide reference the `WARP_API_KEY` environment variable. + +```bash +export WARP_API_KEY="wk-..." +``` + +Replace `wk-...` with the key you created earlier. + +## 2. Create your first run + +Submit a prompt to start an agent run: + +```bash +curl -X POST https://app.warp.dev/api/v1/agent/run \ + -H "Authorization: Bearer $WARP_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "prompt": "Scan the repo for outdated dependencies and summarize the findings.", + "config": { + "environment_id": "<ENV_ID>" + } + }' +``` + +Replace `<ENV_ID>` with your environment ID. Find it with `oz environment list` on the Oz CLI or in the [Oz web app](https://oz.warp.dev). + +:::note +Prefer typed requests? The official [Python SDK](https://github.com/warpdotdev/oz-sdk-python) and [TypeScript SDK](https://github.com/warpdotdev/oz-sdk-typescript) wrap the same API with typed models, retries, and error handling. +::: + +The API returns a `run_id` immediately. The agent starts asynchronously — you can check its status at any time using the run ID. + +## 3. Check run status + +Fetch the current state of the run with the following command. Replace `<RUN_ID>` with the `run_id` from step 2. + +```bash +curl "https://app.warp.dev/api/v1/agent/runs/<RUN_ID>" \ + -H "Authorization: Bearer $WARP_API_KEY" +``` + +The `state` has the following possible values: + +* `QUEUED` - The run is waiting to start. +* `INPROGRESS` - The agent is actively running. +* `SUCCEEDED` - The run completed successfully. +* `FAILED` - The run encountered an error. Check the `status_message` field in the response for details. + +These are the most common states. See the [full API reference](/reference/api-and-sdk/) for all possible values. + +To list all recent runs: + +```bash +curl "https://app.warp.dev/api/v1/agent/runs" \ + -H "Authorization: Bearer $WARP_API_KEY" +``` + +## 4. View the results + +Once the run reaches `SUCCEEDED`, the response includes a `session_link` — a direct URL to the full run transcript, including commands executed, files changed, and agent output. + +You can also view and manage all runs in the [Oz dashboard](https://oz.warp.dev/runs). + +--- + +## Next steps + +* **Read the full API reference** - [Oz API](/reference/api-and-sdk/) documents all endpoint parameters, query filters, and response schemas. +* **Explore the SDKs** - [Python SDK](https://github.com/warpdotdev/oz-sdk-python) and [TypeScript SDK](https://github.com/warpdotdev/oz-sdk-typescript) include typed request/response models, retries, and error handling. +* **See a real-world example** - [Demo: Sentry monitoring with SDK](/reference/api-and-sdk/demo-sentry-monitoring-with-sdk/) shows how to build a webhook handler that triggers agents from production errors. +* **Schedule and automate** - See [Scheduled Agents Quickstart](/agent-platform/cloud-agents/triggers/scheduled-agents-quickstart/) to run agents on a cron, or [Integrations Quickstart](/agent-platform/cloud-agents/integrations/quickstart/) to trigger agents from Slack or Linear. diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/errors/authentication-required.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/authentication-required.mdx new file mode 100644 index 0000000..c6d4770 --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/authentication-required.mdx @@ -0,0 +1,60 @@ +--- +title: authentication_required +description: >- + The API key in the request is invalid, expired, or missing. Generate a new + key and update your client configuration. +--- + +The `authentication_required` error occurs when the API request lacks valid authentication credentials. + +:::note +This is classified as a **platform error** (task state → ERROR) rather than a user error, because it typically indicates a configuration issue with the API key rather than a problem with the task itself. +::: + +--- + +## Details + +* **HTTP Status:** `401 Unauthorized` +* **Retryable:** No +* **Task State:** ERROR + +--- + +## When does this occur? + +This error is returned when: + +* The `Authorization` header is missing from the request +* The API key has been revoked or has expired +* The API key is malformed or invalid + +--- + +## Example response + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/authentication-required/", + "title": "Your API key is invalid or has expired. Please generate a new key and try again.", + "status": 401, + "instance": "/api/v1/agent/tasks", + "error": "Your API key is invalid or has expired. Please generate a new key and try again.", + "retryable": false +} +``` + +--- + +## How to resolve + +1. Generate a new API key from the [Oz web app](https://oz.warp.dev) or via the Oz CLI. +2. Update your client configuration with the new key. +3. Retry the request. + +--- + +## Related + +* [Oz API & SDK](/reference/api-and-sdk/) — API authentication +* [Oz Platform](/agent-platform/cloud-agents/platform/) — API key management diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/errors/budget-exceeded.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/budget-exceeded.mdx new file mode 100644 index 0000000..87acb45 --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/budget-exceeded.mdx @@ -0,0 +1,57 @@ +--- +title: budget_exceeded +description: >- + Your team's configured spending budget limit has been reached. Increase the + budget or wait for the budget period to reset. +--- + +The `budget_exceeded` error occurs when your team has reached the spending budget limit configured in team settings. + +--- + +## Details + +* **HTTP Status:** `403 Forbidden` +* **Retryable:** No +* **Task State:** FAILED + +--- + +## When does this occur? + +This error is returned when: + +* Your team has set a spending budget cap, and the current period's usage has reached that cap +* A cloud agent task, scheduled run, or integration-triggered run attempts to start but would exceed the budget + +The `title` field in the response will describe the specific budget constraint. + +--- + +## Example response + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/budget-exceeded/", + "title": "Monthly spending budget of $50 has been reached.", + "status": 403, + "instance": "/api/v1/agent/tasks", + "error": "Monthly spending budget of $50 has been reached.", + "retryable": false +} +``` + +--- + +## How to resolve + +1. Go to your team settings and increase the spending budget, or +2. Wait for the budget period to reset (for example, at the start of the next billing cycle). + +If you are not a team admin, contact your team admin to adjust the budget. + +--- + +## Related + +* [Access, Billing, and Identity](/agent-platform/cloud-agents/team-access-billing-and-identity/) — Budget configuration and billing details diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/errors/conflict.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/conflict.mdx new file mode 100644 index 0000000..ff198b7 --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/conflict.mdx @@ -0,0 +1,57 @@ +--- +title: conflict +description: >- + The request conflicts with the current state of the resource. Wait for the + resource to reach the expected state and retry. +--- + +The `conflict` error occurs when a request cannot be completed because the resource is in a state that conflicts with the requested operation. + +--- + +## Details + +* **HTTP Status:** `409 Conflict` +* **Retryable:** Yes +* **Task State:** FAILED + +--- + +## When does this occur? + +This error is returned when: + +* You attempt to cancel a task that is still in the **pending** state (the task has not yet been claimed by a worker) + +The operation can typically succeed once the resource transitions to the expected state. + +--- + +## Example response + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/conflict/", + "title": "Pending agent runs cannot be cancelled, retry after a moment.", + "status": 409, + "instance": "/api/v1/agent/tasks/abc123/cancel", + "error": "Pending agent runs cannot be cancelled, retry after a moment.", + "retryable": true +} +``` + +--- + +## How to resolve + +1. Wait a moment for the resource to transition to the expected state. +2. Retry the request. + +For task cancellation specifically, wait until the task moves from **pending** to **in progress** before attempting to cancel. + +--- + +## Related + +* [Managing Cloud Agents](/agent-platform/cloud-agents/managing-cloud-agents/) — Viewing and managing agent tasks +* [Oz API & SDK](/reference/api-and-sdk/) — API reference for managing agent tasks diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/errors/content-policy-violation.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/content-policy-violation.mdx new file mode 100644 index 0000000..2306e28 --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/content-policy-violation.mdx @@ -0,0 +1,60 @@ +--- +title: content_policy_violation +description: >- + The task prompt or environment setup commands were flagged by the platform's + automated content policy checks. +--- + +The `content_policy_violation` error occurs when the task prompt or environment setup commands are flagged by the platform's automated content policy checks. + +--- + +## Details + +* **HTTP Status:** `403 Forbidden` +* **Retryable:** No +* **Task State:** FAILED + +--- + +## When does this occur? + +This error is returned when: + +* The task prompt contains content that violates Warp's usage policies +* The environment setup commands contain patterns flagged as potentially harmful +* The automated content classifier determines the task should be blocked + +:::note +For security reasons, the error message is intentionally generic and does not describe what specifically was flagged. +::: + +--- + +## Example response + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/content-policy-violation/", + "title": "Unable to start cloud agent. Please try again or contact support if the issue persists.", + "status": 403, + "instance": "/api/v1/agent/tasks", + "error": "Unable to start cloud agent. Please try again or contact support if the issue persists.", + "retryable": false, + "trace_id": "abc123..." +} +``` + +--- + +## How to resolve + +1. Review your task prompt and environment setup commands to ensure they comply with [Warp's usage policies](https://www.warp.dev/terms-of-service). +2. If you believe this was flagged in error, contact [Warp support](/support-and-community/troubleshooting-and-support/sending-us-feedback/) and include the `trace_id` from the error response. + +--- + +## Related + +* [Cloud Agents Overview](/agent-platform/cloud-agents/overview/) — How cloud agent tasks work +* [Environments](/agent-platform/cloud-agents/environments/) — Configuring setup commands diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/errors/environment-setup-failed.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/environment-setup-failed.mdx new file mode 100644 index 0000000..f03c20c --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/environment-setup-failed.mdx @@ -0,0 +1,66 @@ +--- +title: environment_setup_failed +description: >- + The cloud agent's environment failed to initialize. Check repo URLs, setup + commands, and working directory paths. +--- + +The `environment_setup_failed` error occurs when the cloud agent's runtime environment could not be initialized. This covers failures during any phase of environment setup, including repository cloning, setup command execution, working directory resolution, and MCP server startup. + +:::note +Although this returns HTTP 500, it is classified as a **user error** (task state → FAILED) because the failure is caused by the environment configuration, not by Warp's infrastructure. +::: + +--- + +## Details + +* **HTTP Status:** `500 Internal Server Error` +* **Retryable:** No +* **Task State:** FAILED + +--- + +## When does this occur? + +This error is returned when any part of the environment initialization process fails: + +* **Git clone failed** — The repository URL is incorrect, the branch does not exist, or the agent does not have access to the repository +* **Setup command failed** — A command in the environment's setup commands list exited with an error (for example, missing dependencies, script errors) +* **Working directory not found** — The configured working directory does not exist after cloning +* **MCP server startup failed** — An MCP server configured for the environment could not start + +The `title` field in the response will describe the specific setup failure. + +--- + +## Example response + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/environment-setup-failed/", + "title": "Failed to clone repository: branch 'main' not found in acme/backend", + "status": 500, + "instance": "/api/v1/agent/tasks", + "error": "Failed to clone repository: branch 'main' not found in acme/backend", + "retryable": false +} +``` + +--- + +## How to resolve + +1. **Check repository configuration** — Verify the repository URL and branch name in your [environment settings](/agent-platform/cloud-agents/environments/). Ensure the repository exists and is accessible. +2. **Check setup commands** — Run the setup commands locally to confirm they work. Look for missing dependencies, incorrect paths, or syntax errors. +3. **Check working directory** — Ensure the working directory path exists relative to the cloned repository root. +4. **Check MCP server configuration** — Verify MCP server startup commands and that any required dependencies or credentials are available. See [MCP Servers for Agents](/reference/cli/mcp-servers/). +5. **Check secrets** — If setup commands reference environment variables from [secrets](/agent-platform/cloud-agents/secrets/), verify the secrets are configured and in scope. + +--- + +## Related + +* [Environments](/agent-platform/cloud-agents/environments/) — Configuring cloud agent environments +* [Secrets](/agent-platform/cloud-agents/secrets/) — Managing credentials for agent environments +* [MCP Servers for Agents](/reference/cli/mcp-servers/) — Configuring MCP servers diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/errors/external-authentication-required.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/external-authentication-required.mdx new file mode 100644 index 0000000..531b94d --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/external-authentication-required.mdx @@ -0,0 +1,117 @@ +--- +title: external_authentication_required +description: >- + The task requires access to an external service (GitHub, Slack, Linear, + etc.) that hasn't been authorized. Follow the auth_url to grant access. +--- + +The `external_authentication_required` error occurs when a cloud agent task needs access to an external service that the user hasn't authorized, or when the Warp GitHub App doesn't have access to the required repositories. + +--- + +## Details + +* **HTTP Status:** `401 Unauthorized` +* **Retryable:** No +* **Task State:** FAILED + +--- + +## When does this occur? + +This error is returned when: + +* **GitHub not connected** — Your Warp account is not linked to a GitHub account, but the task's environment includes GitHub repositories +* **Repository inaccessible** — The Warp GitHub App is not installed on, or does not have access to, one or more repositories required by the task's environment +* **Account matching failed** — A Slack or Linear user who triggered the task cannot be matched to a Warp account + +--- + +## Additional metadata fields + +This error includes extra fields beyond the standard response format: + +* **`provider`** — The external service name (for example, `"github"`, `"slack"`, `"linear"`) +* **`auth_url`** — A URL to complete the authorization flow (when available) +* **`inaccessible_repos`** — A list of repository names the agent cannot access (when applicable) + +--- + +## Example responses + +### GitHub user not connected + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/external-authentication-required/", + "title": "User is not connected to GitHub", + "status": 401, + "instance": "/api/v1/agent/tasks", + "error": "User is not connected to GitHub. Authorize access here: https://...", + "retryable": false, + "provider": "github", + "auth_url": "https://github.com/login/oauth/authorize?..." +} +``` + +### Repository inaccessible + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/external-authentication-required/", + "title": "User does not have access to the following repositories in the environment: acme/backend", + "status": 401, + "detail": "inaccessible repos: acme/backend", + "instance": "/api/v1/agent/tasks", + "error": "User does not have access to the following repositories in the environment: acme/backend (inaccessible repos: acme/backend)", + "retryable": false, + "provider": "github", + "auth_url": "https://github.com/apps/warp-dev/installations/new", + "inaccessible_repos": ["acme/backend"] +} +``` + +### Account matching failed (Slack/Linear) + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/external-authentication-required/", + "title": "Unable to locate your Warp account", + "status": 401, + "instance": "/api/v1/agent/tasks", + "error": "Unable to locate your Warp account", + "retryable": false, + "provider": "slack" +} +``` + +--- + +## How to resolve + +### GitHub not connected + +1. Follow the `auth_url` in the response to connect your GitHub account to Warp. +2. Complete the OAuth authorization flow. +3. Retry the task. + +### Repository inaccessible + +1. Follow the `auth_url` to install or reconfigure the Warp GitHub App. +2. Ensure the app has access to all repositories listed in `inaccessible_repos`. +3. Retry the task. + +If you are using a **team API key** (service account), ensure the Warp GitHub App is installed on the organization that owns the repositories. + +### Account matching failed + +1. Ensure your Slack or Linear account is associated with the same email as your Warp account. +2. If using Slack, verify the Warp Slack integration is installed in your workspace. +3. Contact your team admin if the issue persists. + +--- + +## Related + +* [Environments](/agent-platform/cloud-agents/environments/) — Configuring GitHub repositories for cloud agent environments +* [Integrations](/agent-platform/cloud-agents/integrations/) — Setting up Slack and Linear integrations diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/errors/feature-not-available.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/feature-not-available.mdx new file mode 100644 index 0000000..2da615e --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/feature-not-available.mdx @@ -0,0 +1,59 @@ +--- +title: feature_not_available +description: >- + The requested feature is not included in your current plan. Upgrade your + team's plan to access this capability. +--- + +The `feature_not_available` error occurs when you attempt to use a feature or capability that is not included in your team's current plan. + +--- + +## Details + +* **HTTP Status:** `403 Forbidden` +* **Retryable:** No +* **Task State:** FAILED + +--- + +## When does this occur? + +This error is returned when: + +* You attempt to use a feature that requires a higher-tier plan (for example, certain integrations, advanced capabilities, or self-hosted execution) +* A cloud agent or integration trigger tries to access a feature gated behind a plan upgrade + +The `title` field in the response will describe the specific feature that is unavailable. + +--- + +## Example response + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/feature-not-available/", + "title": "Slack integration requires a Build plan or higher.", + "status": 403, + "instance": "/api/v1/agent/tasks", + "error": "Slack integration requires a Build plan or higher.", + "retryable": false +} +``` + +--- + +## How to resolve + +1. Check which plan your team is on in your team's billing settings. +2. Upgrade to a plan that includes the required feature. +3. Retry the operation. + +For plan comparisons and feature availability, see [Access, Billing, and Identity](/agent-platform/cloud-agents/team-access-billing-and-identity/). + +--- + +## Related + +* [Access, Billing, and Identity](/agent-platform/cloud-agents/team-access-billing-and-identity/) — Plan requirements and feature availability +* [Integrations](/agent-platform/cloud-agents/integrations/) — Integration requirements by plan diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/errors/index.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/index.mdx new file mode 100644 index 0000000..5a7466c --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/index.mdx @@ -0,0 +1,89 @@ +--- +title: Errors Overview +description: >- + Reference for all error codes returned by the Oz platform API. Each error + includes an HTTP status, machine-readable code, and actionable resolution + steps. +--- + +When the Oz platform API encounters an error, it returns a structured JSON response following [RFC 7807 (Problem Details for HTTP APIs)](https://datatracker.ietf.org/doc/html/rfc7807). Every error response includes a machine-readable error code, a human-readable message, and metadata to help you diagnose and resolve the issue. + +--- + +## Response format + +All error responses share this structure: + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/invalid-request/", + "title": "The request contains invalid or missing parameters.", + "status": 400, + "detail": "schedule_id is required", + "instance": "/api/v1/agent/tasks", + "error": "The request contains invalid or missing parameters. (schedule_id is required)", + "retryable": false, + "trace_id": "abc123def456..." +} +``` + +Error responses use the `application/problem+json` content type per RFC 7807. + +### Field reference + +* **`type`** — A URI identifying the error type. Links to the documentation page for that error. +* **`title`** — A short, human-readable summary of the problem. +* **`status`** — The HTTP status code for this response. +* **`detail`** — Additional context specific to this occurrence of the error. Not always present. +* **`instance`** — The request path that produced the error. +* **`error`** — A backward-compatible field combining `title` and `detail` (for older clients). When `detail` is present, formatted as `"title (detail)"`. +* **`retryable`** — Whether this request can be retried. If `true`, the platform may automatically retry the operation. +* **`trace_id`** — An OpenTelemetry trace ID, included when available. Reference this when contacting support. + +Some errors include additional metadata fields (for example, `auth_url`, `provider`, or `inaccessible_repos`). These are documented on each error's page. + +--- + +## Error categories + +Errors are split into two categories based on what caused the failure: + +### User errors + +These indicate something the caller needs to fix. When a cloud agent task encounters a user error, the task transitions to the **FAILED** state. + +* [`insufficient_credits`](/reference/api-and-sdk/troubleshooting/errors/insufficient-credits/) — Team has no remaining Add-on Credits +* [`feature_not_available`](/reference/api-and-sdk/troubleshooting/errors/feature-not-available/) — Feature not included in your current plan +* [`external_authentication_required`](/reference/api-and-sdk/troubleshooting/errors/external-authentication-required/) — External service authorization needed +* [`not_authorized`](/reference/api-and-sdk/troubleshooting/errors/not-authorized/) — Insufficient permissions for the operation +* [`invalid_request`](/reference/api-and-sdk/troubleshooting/errors/invalid-request/) — Malformed request or invalid parameters +* [`resource_not_found`](/reference/api-and-sdk/troubleshooting/errors/resource-not-found/) — Referenced resource does not exist +* [`budget_exceeded`](/reference/api-and-sdk/troubleshooting/errors/budget-exceeded/) — Spending budget limit reached +* [`integration_disabled`](/reference/api-and-sdk/troubleshooting/errors/integration-disabled/) — Integration is disabled +* [`integration_not_configured`](/reference/api-and-sdk/troubleshooting/errors/integration-not-configured/) — Integration setup is incomplete +* [`operation_not_supported`](/reference/api-and-sdk/troubleshooting/errors/operation-not-supported/) — Operation not supported for this resource or state +* [`environment_setup_failed`](/reference/api-and-sdk/troubleshooting/errors/environment-setup-failed/) — Cloud agent environment failed to initialize +* [`content_policy_violation`](/reference/api-and-sdk/troubleshooting/errors/content-policy-violation/) — Task flagged by content policy checks +* [`conflict`](/reference/api-and-sdk/troubleshooting/errors/conflict/) — Request conflicts with the current resource state (retryable) + +### Platform errors + +These indicate a Warp-side issue. When a cloud agent task encounters a platform error, the task transitions to the **ERROR** state. Retryable errors are automatically retried before the task is marked as failed. + +* [`authentication_required`](/reference/api-and-sdk/troubleshooting/errors/authentication-required/) — Invalid or expired API key +* [`resource_unavailable`](/reference/api-and-sdk/troubleshooting/errors/resource-unavailable/) — Transient infrastructure issue (retryable) +* [`internal_error`](/reference/api-and-sdk/troubleshooting/errors/internal-error/) — Unexpected server-side error (retryable) + +--- + +## Using the `trace_id` + +When an error response includes a `trace_id`, you can include it when [contacting Warp support](/support-and-community/troubleshooting-and-support/sending-us-feedback/) to help the team locate the specific request in internal logs. This is especially useful for `internal_error` and `resource_unavailable` errors. + +--- + +## Related + +* [Oz API & SDK](/reference/api-and-sdk/) — API reference for creating and managing agent tasks +* [Cloud Agents Overview](/agent-platform/cloud-agents/overview/) — How cloud agents work +* [Access, Billing, and Identity](/agent-platform/cloud-agents/team-access-billing-and-identity/) — Plan requirements and billing details diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/errors/insufficient-credits.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/insufficient-credits.mdx new file mode 100644 index 0000000..fab6045 --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/insufficient-credits.mdx @@ -0,0 +1,62 @@ +--- +title: insufficient_credits +description: >- + Your team has exhausted all Add-on Credits for cloud agent usage. Purchase + more credits from your team's billing settings to continue. +--- + +The `insufficient_credits` error occurs when your team has no remaining Add-on Credits to run cloud agents or integrations. + +--- + +## Details + +* **HTTP Status:** `403 Forbidden` +* **Retryable:** No +* **Task State:** FAILED + +--- + +## When does this occur? + +This error is returned when: + +* Your team's Add-on Credits balance has reached zero +* A cloud agent task, scheduled run, or integration-triggered run (Slack, Linear) attempts to start but cannot be billed + +Cloud agent runs consume credits based on usage. When credits are depleted, no new runs can start until credits are replenished. + +--- + +## Example response + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/insufficient-credits/", + "title": "Your team has run out of Add-on Credits. Purchase more credits in your team's billing settings to continue.", + "status": 403, + "instance": "/api/v1/agent/tasks", + "title": "Your team has run out of add-on credits. Purchase more credits in your team's billing settings to continue.", + "status": 403, + "instance": "/api/v1/agent/tasks", + "error": "Your team has run out of add-on credits. Purchase more credits in your team's billing settings to continue.", + "retryable": false +} +``` + +--- + +## How to resolve + +1. Go to your team's billing settings in the [Oz web app](https://oz.warp.dev) or Warp desktop app. +2. Purchase additional Add-on Credits. +3. Retry the failed operation. + +If you are not a team admin, contact your team admin to purchase credits. + +--- + +## Related + +* [Access, Billing, and Identity](/agent-platform/cloud-agents/team-access-billing-and-identity/) — Credit billing and plan requirements +* [Cloud Agents Overview](/agent-platform/cloud-agents/overview/) — Billing and plan requirements for cloud agents diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/errors/integration-disabled.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/integration-disabled.mdx new file mode 100644 index 0000000..1c22831 --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/integration-disabled.mdx @@ -0,0 +1,55 @@ +--- +title: integration_disabled +description: >- + The integration (Slack, Linear, etc.) is currently disabled in the Oz + settings. Enable it to continue. +--- + +The `integration_disabled` error occurs when a task targets an integration that is currently disabled in the Oz settings. + +--- + +## Details + +* **HTTP Status:** `403 Forbidden` +* **Retryable:** No +* **Task State:** FAILED + +--- + +## When does this occur? + +This error is returned when: + +* A Slack message, Linear issue, or other integration event triggers a cloud agent, but the corresponding integration has been disabled in the Oz settings +* The integration was previously active but has been turned off by a team admin + +--- + +## Example response + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/integration-disabled/", + "title": "This integration is disabled. Please enable it in Oz.", + "status": 403, + "instance": "/api/v1/agent/tasks", + "error": "This integration is disabled. Please enable it in Oz.", + "retryable": false +} +``` + +--- + +## How to resolve + +1. Go to the [Oz integrations page](https://oz.warp.dev/integrations). +2. Enable the integration that was disabled. +3. Retry the triggering event or task. + +--- + +## Related + +* [Integrations](/agent-platform/cloud-agents/integrations/) — Configuring Slack, Linear, and GitHub integrations +* [Oz Web App](/agent-platform/cloud-agents/oz-web-app/) — Managing integrations via the web interface diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/errors/integration-not-configured.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/integration-not-configured.mdx new file mode 100644 index 0000000..c2ce1f4 --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/integration-not-configured.mdx @@ -0,0 +1,68 @@ +--- +title: integration_not_configured +description: >- + The integration's setup is incomplete. Visit the setup URL to finish + configuring the integration. +--- + +The `integration_not_configured` error occurs when a task requires an integration whose setup has not been completed (for example, missing OAuth tokens or unfinished configuration steps). + +--- + +## Details + +* **HTTP Status:** `400 Bad Request` +* **Retryable:** No +* **Task State:** FAILED + +--- + +## When does this occur? + +This error is returned when: + +* An integration (Slack, Linear, etc.) was partially set up but the configuration was not completed +* Required OAuth tokens or credentials for the integration are missing or expired +* The integration was installed but additional setup steps were not finished + +--- + +## Additional metadata fields + +This error includes extra fields beyond the standard response format: + +* **`integration_name`** — The name of the integration that needs configuration +* **`setup_url`** — A URL to the integration setup page where you can complete configuration + +--- + +## Example response + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/integration-not-configured/", + "title": "Slack integration is not configured", + "status": 400, + "instance": "/api/v1/agent/tasks", + "error": "Slack integration is not configured", + "retryable": false, + "integration_name": "slack", + "setup_url": "https://oz.warp.dev/integrations" +} +``` + +--- + +## How to resolve + +1. Visit the `setup_url` provided in the response metadata (or go to the [Oz integrations page](https://oz.warp.dev/integrations)). +2. Complete all setup steps for the integration. +3. Retry the triggering event or task. + +--- + +## Related + +* [Integrations](/agent-platform/cloud-agents/integrations/) — Integration setup guides +* [Slack Integration](/agent-platform/cloud-agents/integrations/slack/) — Slack-specific setup +* [Linear Integration](/agent-platform/cloud-agents/integrations/linear/) — Linear-specific setup diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/errors/internal-error.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/internal-error.mdx new file mode 100644 index 0000000..5da7583 --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/internal-error.mdx @@ -0,0 +1,60 @@ +--- +title: internal_error +description: >- + An unexpected server-side error occurred. The platform will automatically + retry. Contact support if the issue persists. +--- + +The `internal_error` is a catch-all for unexpected server-side errors. The platform automatically retries these errors before marking the task as failed. + +--- + +## Details + +* **HTTP Status:** `500 Internal Server Error` +* **Retryable:** Yes (automatic) +* **Task State:** ERROR + +--- + +## When does this occur? + +This error is returned when: + +* An unexpected condition occurred on the server that does not match any specific error category +* An internal service dependency failed or timed out +* An unclassified error occurred during task processing + +--- + +## Example response + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/internal-error/", + "title": "An unexpected error occurred. Please try again later. If the issue persists, contact support.", + "status": 500, + "instance": "/api/v1/agent/tasks", + "error": "An unexpected error occurred. Please try again later. If the issue persists, contact support.", + "retryable": true, + "trace_id": "abc123..." +} +``` + +--- + +## How to resolve + +No action is typically needed — the platform will automatically retry the task. + +If the error persists: + +1. Wait a few minutes and try again. +2. Contact [Warp support](/support-and-community/troubleshooting-and-support/sending-us-feedback/) and include the `trace_id` from the error response. + +--- + +## Related + +* [Cloud Agents Overview](/agent-platform/cloud-agents/overview/) — How cloud agent tasks work +* [Cloud Agents FAQs](/agent-platform/cloud-agents/faqs/) — Common questions about cloud agents diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/errors/invalid-request.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/invalid-request.mdx new file mode 100644 index 0000000..86a8303 --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/invalid-request.mdx @@ -0,0 +1,60 @@ +--- +title: invalid_request +description: >- + The request body is malformed, missing required fields, or contains invalid + parameter values. +--- + +The `invalid_request` error occurs when the API request is malformed or contains invalid parameters. + +--- + +## Details + +* **HTTP Status:** `400 Bad Request` +* **Retryable:** No +* **Task State:** FAILED + +--- + +## When does this occur? + +This error is returned when: + +* Required fields are missing from the request body (for example, `prompt` or `schedule_id`) +* Parameter values are invalid or out of range +* The request body cannot be parsed (malformed JSON) +* A referenced identifier is in the wrong format +* A team-owned task references a personal environment (team tasks require team-scoped environments) + +The `detail` field in the response will describe the specific validation issue. + +--- + +## Example response + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/invalid-request/", + "title": "The request contains invalid or missing parameters.", + "status": 400, + "detail": "schedule_id is required", + "instance": "/api/v1/agent/tasks", + "error": "The request contains invalid or missing parameters. (schedule_id is required)", + "retryable": false +} +``` + +--- + +## How to resolve + +1. Check the `detail` field for the specific validation issue. +2. Correct the request parameters according to the [API documentation](/reference/api-and-sdk/). +3. Retry the request. + +--- + +## Related + +* [Oz API & SDK](/reference/api-and-sdk/) — API request format and parameters diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/errors/not-authorized.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/not-authorized.mdx new file mode 100644 index 0000000..edcde85 --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/not-authorized.mdx @@ -0,0 +1,58 @@ +--- +title: not_authorized +description: >- + The authenticated user or API key does not have permission to perform the + requested operation. +--- + +The `not_authorized` error occurs when the authenticated principal (user or API key) does not have sufficient permissions to perform the requested operation. + +--- + +## Details + +* **HTTP Status:** `403 Forbidden` +* **Retryable:** No +* **Task State:** FAILED + +--- + +## When does this occur? + +This error is returned when: + +* You attempt to access a resource owned by another team or user +* Your API key does not have the required scope for the operation +* You try to perform an admin-level operation without admin privileges +* A team-level operation is attempted by a user who is not a member of the team + +--- + +## Example response + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/not-authorized/", + "title": "You do not have permission for this operation.", + "status": 403, + "detail": "user is not a member of the team", + "instance": "/api/v1/agent/tasks/abc123", + "error": "You do not have permission for this operation. (user is not a member of the team)", + "retryable": false +} +``` + +--- + +## How to resolve + +1. Verify that the API key or user account belongs to the correct team. +2. Check that your role has the necessary permissions for the operation. +3. Contact a team admin if you need elevated access. + +--- + +## Related + +* [Access, Billing, and Identity](/agent-platform/cloud-agents/team-access-billing-and-identity/) — Permission model and identity +* [Oz API & SDK](/reference/api-and-sdk/) — API authentication and authorization diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/errors/operation-not-supported.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/operation-not-supported.mdx new file mode 100644 index 0000000..7370ee3 --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/operation-not-supported.mdx @@ -0,0 +1,59 @@ +--- +title: operation_not_supported +description: >- + The requested operation is not supported for this resource or its current + state. +--- + +The `operation_not_supported` error occurs when you attempt an operation that is not currently supported for the given resource or its current state. + +--- + +## Details + +* **HTTP Status:** `422 Unprocessable Entity` +* **Retryable:** No +* **Task State:** FAILED + +--- + +## When does this occur? + +This error is returned when: + +* You attempt to cancel a **self-hosted** agent run via the API (self-hosted runs must be cancelled through the hosting infrastructure) +* You attempt to cancel a **local** agent run via the API (local runs must be cancelled from the source client) +* You attempt to cancel a run triggered via **GitHub Actions** (these must be cancelled through the GitHub Actions workflow view) + +--- + +## Example response + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/operation-not-supported/", + "title": "Self-hosted agent runs cannot be cancelled with the API.", + "status": 422, + "instance": "/api/v1/agent/tasks/abc123/cancel", + "error": "Self-hosted agent runs cannot be cancelled with the API.", + "retryable": false +} +``` + +--- + +## How to resolve + +1. Check the error message to understand which operation is unsupported and why. +2. Use the appropriate method for the operation: + * **Self-hosted runs** — Cancel through your hosting infrastructure. + * **Local runs** — Cancel from the Warp desktop app or terminal session. + * **GitHub Actions runs** — Cancel via the GitHub Actions workflow view. + +--- + +## Related + +* [Cloud Agents Overview](/agent-platform/cloud-agents/overview/) — How cloud agent tasks work +* [Self-Hosting](/agent-platform/cloud-agents/self-hosting/) — Self-hosted agent configuration +* [Oz API & SDK](/reference/api-and-sdk/) — API reference for managing agent tasks diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/errors/resource-not-found.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/resource-not-found.mdx new file mode 100644 index 0000000..058777d --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/resource-not-found.mdx @@ -0,0 +1,59 @@ +--- +title: resource_not_found +description: >- + The requested resource (task, environment, schedule, agent, etc.) does not + exist or has been deleted. +--- + +The `resource_not_found` error occurs when a referenced resource cannot be found. This typically means the resource ID is incorrect, the resource has been deleted, or it belongs to a different team. + +--- + +## Details + +* **HTTP Status:** `404 Not Found` +* **Retryable:** No +* **Task State:** FAILED + +--- + +## When does this occur? + +This error is returned when: + +* A task ID, environment UID, schedule ID, or other resource identifier does not match any existing resource +* The referenced resource has been deleted +* The resource exists but belongs to a different team or user (and you don't have access) + +The `detail` field in the response will describe which resource was not found. + +--- + +## Example response + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/resource-not-found/", + "title": "The requested resource was not found.", + "status": 404, + "detail": "environment abc123 not found", + "instance": "/api/v1/agent/tasks", + "error": "The requested resource was not found. (environment abc123 not found)", + "retryable": false +} +``` + +--- + +## How to resolve + +1. Verify the resource ID is correct and properly formatted. +2. Check that the resource has not been deleted (for example, via the [Oz web app](https://oz.warp.dev) or CLI). +3. Confirm the resource belongs to your team or that you have access to it. + +--- + +## Related + +* [Environments](/agent-platform/cloud-agents/environments/) — Managing cloud agent environments +* [Managing Cloud Agents](/agent-platform/cloud-agents/managing-cloud-agents/) — Viewing and managing agent tasks diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/errors/resource-unavailable.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/resource-unavailable.mdx new file mode 100644 index 0000000..482aa4b --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/errors/resource-unavailable.mdx @@ -0,0 +1,75 @@ +--- +title: resource_unavailable +description: >- + A transient infrastructure issue prevented the task from running. The + platform will automatically retry. No action is needed. +--- + +The `resource_unavailable` error indicates a transient infrastructure issue that prevented the cloud agent task from running. This is automatically retried by the platform. + +--- + +## Details + +* **HTTP Status:** `429 Too Many Requests` or `500 Internal Server Error` +* **Retryable:** Yes (automatic) +* **Task State:** ERROR + +--- + +## When does this occur? + +This error is returned when: + +* **Capacity full (429)** — Cloud agent capacity is temporarily saturated. Your task will be queued and retried automatically. +* **Sandbox creation failed (500)** — A sandbox instance could not be created for the agent. This is typically a transient issue. + +--- + +## Example responses + +### Capacity full + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/resource-unavailable/", + "title": "Agent capacity is temporarily full. Your task will be retried automatically, or you can try again later.", + "status": 429, + "instance": "/api/v1/agent/tasks", + "error": "Agent capacity is temporarily full. Your task will be retried automatically, or you can try again later.", + "retryable": true, + "trace_id": "abc123..." +} +``` + +### Sandbox creation failed + +```json +{ + "type": "/reference/api-and-sdk/troubleshooting/errors/resource-unavailable/", + "title": "Failed to create a sandbox instance for your agent. This is typically a transient issue — your task will be retried automatically.", + "status": 500, + "instance": "/api/v1/agent/tasks", + "error": "Failed to create a sandbox instance for your agent. This is typically a transient issue — your task will be retried automatically.", + "retryable": true, + "trace_id": "abc123..." +} +``` + +--- + +## How to resolve + +No action is typically needed — the platform will automatically retry the task. + +If the error persists after retries: + +1. Try again later when capacity has freed up. +2. Contact [Warp support](/support-and-community/troubleshooting-and-support/sending-us-feedback/) and include the `trace_id` from the error response. + +--- + +## Related + +* [Cloud Agents Overview](/agent-platform/cloud-agents/overview/) — How cloud agent execution works +* [Deployment Patterns](/agent-platform/cloud-agents/deployment-patterns/) — Execution models and infrastructure diff --git a/src/content/docs/reference/api-and-sdk/troubleshooting/index.mdx b/src/content/docs/reference/api-and-sdk/troubleshooting/index.mdx new file mode 100644 index 0000000..f183b8f --- /dev/null +++ b/src/content/docs/reference/api-and-sdk/troubleshooting/index.mdx @@ -0,0 +1,12 @@ +--- +title: API Troubleshooting +description: >- + Troubleshooting resources for the Oz API and SDK, including a full reference + for all platform error codes. +--- + +When the Oz platform API encounters an error, it returns a structured response following [RFC 7807 (Problem Details for HTTP APIs)](https://datatracker.ietf.org/doc/html/rfc7807) with a machine-readable error code, HTTP status, and actionable resolution steps. + +## Resources + +* [**Errors**](/reference/api-and-sdk/troubleshooting/errors/) — Full reference for all API error codes, including causes, example responses, and resolution steps diff --git a/src/content/docs/reference/cli/agent-profiles.mdx b/src/content/docs/reference/cli/agent-profiles.mdx new file mode 100644 index 0000000..51b858b --- /dev/null +++ b/src/content/docs/reference/cli/agent-profiles.mdx @@ -0,0 +1,51 @@ +--- +title: Agent profiles +description: >- + Use agent profiles with the Oz CLI to control what the agent can access, how + it behaves, and where it can act. +--- + +Agent profiles control three things: + +* **What the agent can do** — file access, command execution, and MCP server usage +* **How the agent works** — model selection, autonomy level, and response style +* **Where the agent can act** — directory allowlists and denylists + +You can create and configure agent profiles in the Warp app. For detailed instructions, see [Agent Profiles & Permissions](/agent-platform/capabilities/agent-profiles-permissions/). + +Agent profiles are automatically synced to each host where you have Warp installed, so you can use them remotely as well. + +:::note +**Tip:** For CLI usage, create a dedicated profile. The CLI will fail if the agent tries to execute a prohibited action, so make sure your profile allows the directories, commands, and MCP servers you plan to use. +::: + +:::caution +The default profile for CLI usage is broadly permissive and gives the agent the ability to read and write files, apply code diffs, and execute commands (with a default denylist). The agent does not have the ability to use MCP servers by default. +::: + +## Using a profile with the CLI + +1. Find the profile ID using `oz agent profile list`: + +```sh +$ oz agent profile list ++--------------+------------------------+ +| Name | ID | ++=======================================+ +| Default | AnTb02PZfrkVC9l4V15eH1 | +|--------------+------------------------| +| Coding | CWhozDJPdPCsjJ1pSG0HCN | +|--------------+------------------------| +| Command Line | hV6n5dNm7ThQVlOiPF8DLS | ++--------------+------------------------+ +``` + +2. Pass that ID using the `--profile` flag: + +```sh +$ oz agent run --profile CWhozDJPdPCsjJ1pSG0HCN --prompt "update my CI pipeline to use nextest" +``` + +:::note +The `--profile` flag is available on `oz agent run` only. Cloud runs (`oz agent run-cloud`) do not use agent profiles. +::: diff --git a/src/content/docs/reference/cli/api-keys.mdx b/src/content/docs/reference/cli/api-keys.mdx new file mode 100644 index 0000000..cc02aa6 --- /dev/null +++ b/src/content/docs/reference/cli/api-keys.mdx @@ -0,0 +1,95 @@ +--- +title: API keys +description: >- + Create and manage API keys for authenticating the Oz CLI and cloud agents. +--- + +API keys let the Oz CLI and cloud agents authenticate without human interaction. Use API keys for CI pipelines, headless servers, VMs, Codespaces, containers, and other automated environments. + +## Creating API keys + +You can create an API key from your settings in Warp: + +1. Click your profile photo in the top-right corner, then click **Settings**. +2. In the sidebar, expand **Cloud platform** and click **Oz Cloud API Keys**. +3. In the API Keys section, click **+ Create API Key**. +4. Name the key and choose an expiration (1 day, 30 days, 90 days, or never). +5. Select the key type: + * `Personal` - Tied to your individual Warp account + * `Team` - Tied to your team, not any individual user + +:::note +When an agent needs to make code changes (e.g., opening pull requests, pushing branches, or writing to a repository), you have two options: + +* Use a **personal API key** to authenticate as you. The agent runs with your GitHub permissions, and code changes are attributed to your GitHub account. +* Use a **team API key** with [team GitHub authorization](/agent-platform/cloud-agents/team-access-billing-and-identity/#team-github-authorization) configured. The agent authenticates with the Oz by Warp GitHub App, and code changes are not attributed to any individual user. +::: + +:::note +Team keys without GitHub App authorization are the right fit for automated workflows that don't require writing to GitHub, such as analysis, monitoring, or triage. +::: + +6. Click **Create key**. +7. Copy the raw API key and store it securely. **You won't be able to see it again after closing the dialog.** + +![API key management interface in Warp settings](../../../../assets/reference/api-key-management.png) + +## Personal vs team API keys + +Warp supports two types of API keys, each with different billing and identity behavior: + +* **Personal API keys** - Cloud agent runs authenticate as you. These runs can use your personal base credits before drawing from team Add-on Credits, just like running an agent from the Warp app or triggering one via Slack or Linear. +* **Team API keys** - Cloud agent runs are not tied to any individual user. These runs can only draw from your team's pool of Add-on Credits. They cannot use any individual's base credits. When [team GitHub authorization](/agent-platform/cloud-agents/team-access-billing-and-identity/#team-github-authorization) is configured, team key runs can also clone repositories and open pull requests using the Oz by Warp GitHub App. + +Team API keys are useful for fully automated workflows, CI/CD pipelines, and scheduled tasks where no specific user context is needed. For billing details, see [Access, Billing, and Identity Permissions](/agent-platform/cloud-agents/team-access-billing-and-identity/). + +## Authenticating with API keys + +You can authenticate with an API key in the CLI using either an environment variable or command flag. We recommend environment variables for security and easier reuse across multiple commands. + +**Via environment variable (recommended):** + +```sh +$ export WARP_API_KEY="wk-xxx..." +$ oz agent run --prompt "analyze this codebase" +``` + +**Via command flag:** + +```sh +$ oz agent run --api-key "wk-xxx..." --prompt "analyze this codebase" +``` + +:::note +API keys start with the prefix `wk-`. If your key doesn't have this prefix, it may be invalid or from an older format. +::: + +## Managing API keys + +The API Keys section in **Settings** > **Cloud platform** > **Oz Cloud API Keys** displays all your active keys with the following information: + +* **Name** - The name you assigned when creating the key +* **Key** - A masked suffix (`wk-**xxxx`) to help identify the key +* **Scope** - Whether the key is Personal or Team +* **Created** - When the key was created +* **Last used** - When the key was last used for authentication +* **Expires at** - The key's expiration date, or "Never" if it doesn't expire + +### Deleting API keys + +To delete an API key: + +1. Go to **Settings** > **Cloud platform** > **Oz Cloud API Keys**. +2. Find the key you want to delete in the API Keys list. +3. Click the delete icon next to the key. + +Deleted keys are immediately invalidated and cannot be recovered. Any services or scripts using the deleted key will lose access. + +## Best practices + +* **Use environment variables** - Avoid passing API keys directly in commands where they may be logged or visible in shell history. +* **Set appropriate expiration** - Use shorter expiration times for development and testing; consider longer durations for stable production workflows. +* **Use team keys for automation** - For CI/CD and scheduled tasks, team keys provide cleaner billing attribution and don't depend on any individual user's account. +* **Use personal keys or configure team GitHub authorization when agents need to write to GitHub** - Personal keys authenticate as you; team keys can also write to GitHub when [team GitHub authorization](/agent-platform/cloud-agents/team-access-billing-and-identity/#team-github-authorization) is configured via the Admin Panel. +* **Rotate keys periodically** - Create new keys and retire old ones on a regular schedule to limit exposure from compromised credentials. +* **Store securely** - Use secret managers (like 1Password CLI, HashiCorp Vault, or cloud provider secret services) rather than plain text files. diff --git a/src/content/docs/reference/cli/index.mdx b/src/content/docs/reference/cli/index.mdx new file mode 100644 index 0000000..19f1bba --- /dev/null +++ b/src/content/docs/reference/cli/index.mdx @@ -0,0 +1,372 @@ +--- +title: Oz CLI +description: >- + Use the Oz CLI to run, configure, and manage agents from the terminal. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +:::note +**`warp-cli` is deprecated and has been replaced by `oz`.** If you have `warp-cli` installed, it will auto-update to `oz`. All the same commands are available, just replace `warp-cli` with `oz` in your scripts and workflows. +::: + +## What is the Oz CLI? + +The Oz CLI is the command-line tool that lets you run [Cloud Agents](/agent-platform/cloud-agents/overview/) from anywhere, including terminals, scripts, automated systems, or services. + +It's the standard runtime entry point that turns a **prompt** plus **configuration** into an **executable agent task** that runs on either a **Warp-hosted or [self-hosted](/agent-platform/cloud-agents/self-hosting/) runner**. + +With the Oz CLI, you can: + +* Run agents locally for development and debugging +* Run agents on remote machines +* Connect agents to MCP servers like GitHub and Linear +* Configure integrations that connect agents to Slack, Linear, and other trigger surfaces + +## Installing the CLI + +You can install the Oz CLI as part of the Warp desktop app, or as a standalone package. + +### Bundled with Warp + +The Oz CLI is automatically distributed with the Warp desktop app and can be used right away in Warp. To make the CLI globally available, add it to your `PATH`. + +<Tabs> + <TabItem label="macOS"> + To add the Oz CLI to your `PATH`: + + 1. Open the [Command Palette](/terminal/command-palette/) (`CMD+P` ) + 2. In the search field, find and select the **Install Oz CLI Command** action. + + :::note + **Note:** Administrator permissions are required to install the CLI into `/usr/local/bin` . + ::: + </TabItem> + <TabItem label="Windows"> + In the Warp installer, select **Add Warp to PATH**. If you are installing for all users, this will put the CLI on the system path. Otherwise, the CLI is only added to the path for your account. + </TabItem> + <TabItem label="Linux"> + To run the Oz CLI on Linux, use the same command that you'd use to start Warp normally. If you installed Warp via a package manager, it should already be on the system `PATH`. + </TabItem> +</Tabs> + +### Standalone package + +Warp provides standalone packages for the CLI on macOS and Linux, without the Warp app. + +<Tabs> + <TabItem label="macOS"> + On macOS, we recommend that you install and update the standalone CLI with [Homebrew](https://brew.sh/), using the [`warpdotdev/warp` tap](https://github.com/warpdotdev/homebrew-warp): + + ```sh + $ brew tap warpdotdev/warp + $ brew update + $ brew install --cask oz + ``` + + If you're using Warp Preview, install the preview version of the CLI instead: + + ```sh + brew install --cask oz@preview + ``` + + *** + + You can also download the CLI directly from these URLs: + + * [Apple Silicon](https://app.warp.dev/download/cli?os=macos\&package=tar\&arch=aarch64) + * [Intel](https://app.warp.dev/download/cli?os=macos\&package=tar\&arch=x86_64) + * [Apple Silicon, Warp Preview](https://app.warp.dev/download/cli?os=macos\&channel=preview\&package=tar\&arch=aarch64) + * [Intel, Warp Preview](https://app.warp.dev/download/cli?os=macos\&channel=preview\&package=tar\&arch=x86_64) + + :::note + **Note:** These builds do not auto-update. + ::: + </TabItem> + <TabItem label="Linux"> + On Linux, we recommend that you install and update the standalone CLI through your distribution's package manager. We support `apt`, `yum`, and `pacman`. + + 1. Add the Warp package repository for your distribution (see the [installation instructions](/getting-started/quickstart/installation-and-setup/)). + 2. Install either the stable or Preview package (replace `apt` with `yum` or `pacman` as needed): + + ```sh + # Stable + sudo apt install oz-stable + + # Preview (beta/early-access) + sudo apt install oz-preview + + ``` + + :::note + **Note:** The package name (`oz-stable`) differs from the CLI command executable (`oz`). After installation, use the CLI via `oz` commands. + ::: + + *** + + You can also install the CLI by downloading a package directly. These installers automatically add the Warp repository, so future updates come through your package manager: + + * x86-64: [`.deb`](https://app.warp.dev/download/cli?os=linux\&package=deb\&arch=x86_64), [`.rpm`](https://app.warp.dev/download/cli?os=linux\&package=rpm\&arch=x86_64), [pacman](https://app.warp.dev/download/cli?os=linux\&package=pacman\&arch=x86_64) + * aarch64: [`.deb`](https://app.warp.dev/download/cli?os=linux\&package=deb\&arch=aarch64), [`.rpm`](https://app.warp.dev/download/cli?os=linux\&package=rpm\&arch=aarch64), [pacman](https://app.warp.dev/download/cli?os=linux\&package=pacman\&arch=aarch64) + </TabItem> + <TabItem label="Windows"> + A standalone CLI package is not currently available on Windows. To use the Oz CLI on Windows, install the Warp app, which bundles the CLI. + + You can install Warp using [WinGet](https://learn.microsoft.com/en-us/windows/package-manager/winget/): + + ```powershell + winget install Warp.Warp + ``` + + After installation, see [Bundled with Warp](#bundled-with-warp) for instructions on adding the CLI to your `PATH`. + </TabItem> +</Tabs> + +## Running the CLI + +Regardless of your OS or installation method, the CLI command is `oz`. If you're using [Warp Preview](/support-and-community/community/warp-preview-and-alpha-program/), use `oz-preview` instead. + +## Logging in + +The Oz CLI supports two authentication methods, depending on where and how you're running agents. + +* **Interactive login —** best for local machines where you have Warp installed and can authenticate through a browser. +* **API keys** — best for automated or remote environments that need to authenticate without human interaction. + +### Interactive login (local machines) + +Use interactive login when you’re working on a machine where you already use the Warp app, or when you can open a browser to complete authentication. + +If you use the CLI on a host where you're already signed in to Warp, it automatically reuses your existing credentials. + +To authenticate interactively: + +```bash +oz login +``` + +The CLI prints out a URL that you can open in any browser to login to Warp. + +### API key authentication + +Use an API key when the environment must authenticate on its own, such as CI pipelines, headless servers, VMs, Codespaces, or containers. API keys let the CLI authenticate non-interactively. + +For detailed instructions on creating, managing, and using API keys, see [API Keys](/reference/cli/api-keys/). + +**Quick start:** + +```sh +$ export WARP_API_KEY="wk-xxx..." +$ oz agent run --prompt "analyze this codebase" +``` + +--- + +## Running agents + +The Oz CLI offers two ways to run agents, depending on where you want the work to happen: + +**Use `oz agent run` when:** + +* You're developing locally and want immediate feedback +* You need the agent to work with files in your current directory +* You want to inspect and modify the agent's work in real time +* You're debugging or iterating on prompts + +**Use `oz agent run-cloud` when:** + +* You want the agent to run on a remote machine or standardized environment +* You're triggering agent work from CI/CD or automated systems +* You need the agent to run independently of your local session +* You're delegating work that doesn't require your immediate attention + +### Running locally: \`oz agent run\` + +To start an agent, use the `oz agent run` subcommand. You'll need to specify a prompt and, optionally, the [MCP servers](/agent-platform/capabilities/mcp/) and [agent profile](/agent-platform/capabilities/agent-profiles-permissions/) to use. + +```sh +oz agent run --prompt "set up a new Rust crate named warp-cli" +I'll run a few terminal commands to: +- Check if this is a Git repo and Cargo workspace +- Create a new binary crate named warp-cli +``` + +**Key flags:** + +* `--cwd <PATH>` (`-C`) — run from a different directory. +* `--name <NAME>` (`-n`) — label the run for grouping and traceability. +* `--share` — share the session with teammates (see [Collaboration](/reference/cli/#collaboration)). +* `--profile <ID>` — use a specific agent profile (see [Using Agent Profiles](/reference/cli/#using-agent-profiles)). +* `--model <MODEL_ID>` — override the default model (see [Model Choice](/agent-platform/capabilities/model-choice/)). +* `--skill <SPEC>` — use a skill as the base prompt (see [Using Skills](/reference/cli/#using-skills)). +* `--mcp <SPEC>` — start one or more MCP servers before execution (UUID, JSON file path, or inline JSON). Can be repeated. +* `--environment <ID>` (`-e`) — run in a specific cloud environment. +* `--file <PATH>` (`-f`) — load run configuration from a YAML or JSON file. + +The agent will automatically carry out the task you gave it, printing out tool calls and responses as it works. + +By default, the agent runs in your current working directory. To run from a different directory, use the `-C/--cwd` flag. + +### Running agents remotely: \`oz agent run-cloud\` + +Cloud runs dispatch tasks to remote environments. Use cloud runs for: + +* Background processing +* Standardized team configurations +* Remote execution on servers you don't directly access + +```sh +oz agent run-cloud \ + --environment <ENVIRONMENT_ID> \ + --name "Repo summary" \ + --prompt "Summarize this repo and list the top 5 risky areas" \ + --open +``` + +**Key flags** + +* `--environment <ENVIRONMENT_ID>` (`-e`) — select the environment to run in. +* `--no-environment` — run without an environment (not recommended). +* `--open` — view the agent's session in Warp once it's available. +* `--name <NAME>` (`-n`) — label the run for grouping and traceability (see [Naming runs](/reference/cli/#naming-runs) below). +* `--mcp <SPEC>` — start one or more MCP servers before execution (UUID, JSON file path, or inline JSON). Can be repeated. +* `--model <MODEL_ID>` — override the default model. +* `--skill <SPEC>` — use a skill from the environment's repository as the base prompt (see [Using Skills](/reference/cli/#using-skills)). +* `--host <WORKER_ID>` — run on a specific self-hosted worker instead of Warp-hosted infrastructure. +* `--attach <PATH>` — attach an image file to the agent query. Can be repeated (maximum 5). +* `--computer-use` / `--no-computer-use` — enable or disable [Computer Use](/agent-platform/capabilities/computer-use/) for this run. +* `--file <PATH>` (`-f`) — load run configuration from a YAML or JSON file. + +**Key differences from `run`** + +* No `--cwd` — the environment determines the working directory. +* No `--share` — sharing options are on `run`, not `run-cloud`. +* No `--profile` — cloud runs do not use agent profiles. + +#### Naming runs + +The `--name` flag assigns a config name to the run. Use it to group related runs under a shared label so you can filter, search, and track them later. + +**How names work:** + +* **Skill-based runs** — When you run an agent from a [skill](/agent-platform/capabilities/skills/), the name is automatically set to the skill name. You don't need to pass `--name` explicitly. +* **Custom runs** — When you build your own automation (via the CLI, API, or SDK), set `--name` to a consistent value that describes the workflow's intent. + +**Why naming matters:** + +When your team runs many agents across schedules, integrations, and ad-hoc triggers, `name` lets you answer questions like "how many distinct workflows are we running?" and "how often does this particular workflow run?" You can filter runs by name using the `name` query parameter on `GET /agent/runs` in the [Oz API](/reference/api-and-sdk/). + +**Examples:** + +```sh +# Name a recurring workflow for easy tracking +oz agent run-cloud \ + --environment <ENVIRONMENT_ID> \ + --name "nightly-dependency-check" \ + --prompt "Check for outdated dependencies and open a PR with updates" + +# Skill-based runs are named automatically +oz agent run-cloud \ + --environment <ENVIRONMENT_ID> \ + --skill "myorg/backend:code-review" \ + --prompt "review the latest PR" +``` + +**When cloud runs fail** + +* Verify your environment has the correct repository and context. +* Check that your profile allows the commands and MCP servers needed. +* Ensure environment variables are set in the environment, not your local shell. + +#### Reusing saved prompts and Warp Drive objects + +You can reuse saved prompts with `--saved-prompt`, and reference notebooks, workflows, and rules inline in any `--prompt` string. See [Referencing Warp Drive objects](/reference/cli/warp-drive/) for details. + +## Using agent profiles + +Agent profiles control what the agent can do, how it behaves, and where it can act. Use the `--profile` flag with `oz agent run` to apply a specific profile. + +See [Agent profiles](/reference/cli/agent-profiles/) for how to find profile IDs and apply them. + +## Using MCP servers + +MCP servers connect agents to external systems like GitHub, Linear, or Sentry. Use the `--mcp` flag with any of three formats: a Warp MCP server UUID, inline JSON, or a path to a JSON config file. + +See [MCP Servers](/reference/cli/mcp-servers/) for full details, including how to find UUIDs, combine multiple servers, and handle environment variables on remote machines. + +## Using skills + +[Skills](/agent-platform/capabilities/skills/) are reusable instruction sets that teach agents how to perform specific tasks. Use the `--skill` flag to run an agent from a skill stored in a repository. + +See [Skills](/reference/cli/skills/) for supported spec formats and examples for both local and cloud agent runs. + +## Collaboration + +In addition to text-based output, the CLI can share the agent's session for you to access on other devices or in a browser. To enable [Agent Session Sharing](/agent-platform/local-agents/session-sharing/), use the `--share` flag. + +By default, the session is only accessible to the user running the CLI, but you can also share with [Teams](/knowledge-and-collaboration/teams/) or other Warp users: + +```sh +# Share the agent's session with yourself: +$ oz agent run --share --prompt "fix the compiler error" + +# Give specific users view-only access to a session: +$ oz agent run --share firstuser@example.com --share otheruser@example.com --prompt "fix the compiler error" + +# Let any user on your team edit the session: +$ oz agent run --share team:edit --prompt "fix the compiler error" +``` + +The `--share` flag can be repeated, and uses the following syntax: + +* `--share user@email.com` or `--share user@email.com:view` — gives specified user read-only access to the session. +* `--share user@email.com:edit` — gives specified user `user@email.com` read/write access to the session. +* `--share team` or `--share team:view` — gives all members of your team read-only access to the session. +* `--share team:edit` — gives all members of your team read/write access to the session. + +## Additional commands + +The following commands are available for managing and inspecting Oz resources. + +### `oz agent list` + +List all available skills discovered from your environments. Optionally filter by repository: + +```sh +oz agent list +oz agent list --repo owner/repo +``` + +### `oz run list` / `oz run get` + +List and inspect cloud agent runs: + +```sh +# List recent runs (default: 10) +oz run list +oz run list --limit 20 + +# Get details for a specific run +oz run get <RUN_ID> +``` + +### `oz model list` + +List all available models: + +```sh +oz model list +``` + +### `oz environment image list` + +List suggested base images for cloud environments: + +```sh +oz environment image list +``` + +--- + +## Troubleshooting + +For built-in CLI help commands and solutions to common errors — including authentication issues, agent failures, environment problems, and Docker image issues — see [Troubleshooting](/reference/cli/troubleshooting/). diff --git a/src/content/docs/reference/cli/integration-setup.mdx b/src/content/docs/reference/cli/integration-setup.mdx new file mode 100644 index 0000000..9a9074f --- /dev/null +++ b/src/content/docs/reference/cli/integration-setup.mdx @@ -0,0 +1,293 @@ +--- +title: Integration setup +description: >- + Learn how to set up environments and integrations so you can trigger Oz + agents from external tools. +--- + +This article describes the environment and integration setup that is required before you can trigger agents from external tools, like Slack or Linear. You will learn how to: + +* Create and configure the environment needed to run agents +* Connect that environment to your team +* Trigger agents using Slack or Linear + +:::note +**You only need to complete this setup once per Warp team**. After an integration exists, anyone on the team can use it. For example, the first time a teammate triggers an agent from Slack or Linear, they'll be prompted to authorize GitHub with their own account in order for the agent to write back to repos. + +Note: While cloud agents can be run individually via CLI without a team, integrations (Slack, Linear) require team membership. +::: + +:::note +For a quick start guide to Warp integrations, please see the [Integrations Overview](/agent-platform/cloud-agents/integrations/). +::: + +## How integrations and environments work + +Warp integrations connect external tools, like Slack or Linear, to agents that run your code in the background. + +There are three main components to know: + +* **Triggers** provide the context that tells Warp _what_ to run. A trigger could be a Slack message where you tag @Oz, or a Linear issue or comment. +* [**Integrations**](/agent-platform/cloud-agents/integrations/) are what connect the trigger surface (Slack, Linear) to Warp. An integration links the trigger to your [Warp team](/knowledge-and-collaboration/teams/) and handles posting results to the original tool, for example, replying in Slack. +* **Environments** define how and where agents run your code. When an agent is triggered, Warp uses the environment to spin up a container, clone repositories, and execute the agent's workflow. + +``` +Slack or Linear + (trigger) + → +Warp Integration + (connects tools to Warp) + → +Environment + (Docker image + repos + setup) + → +Agent + (runs workflow, opens PRs, posts results) +``` +Setting up an integration consists of three steps. + +1. **Create an environment** for the agent to run your code. +2. **Authorize GitHub** so Warp can clone repositories, write code, debug issues, open pull requests, and more. +3. **Configure** the Oz app with an integration. + +--- + +## Step 1: Creating an environment + +Before you can trigger agents from Slack or Linear, you need an environment. The environment defines how and where Warp runs your code. + +At a minimum, an environment includes: + +* A Docker image +* One or more GitHub repositories +* Optional setup commands + +Typically, you'll create **one environment per codebase** (or closely related set of repos) and reuse it across integrations. + +You can create environments using a guided Agent flow, or directly through the CLI. + +#### Before you begin + +Make sure you have: + +* A GitHub repository (or repositories) that the agent can work in. +* A publicly-accessible Docker image that can build and run your code. Official images like `node`, `python`, or `rust` work for many projects. + +:::note +You only need to create an environment once. It can be reused across Slack, Linear, and terminal triggers. +::: + +### Option 1: Guided environment setup (recommended) + +The fastest way to get started is to use the guided environment setup. Use the `/create-environment` [slash command](/agent-platform/capabilities/slash-commands/) if you want Warp to analyze your repos and suggest an environment configuration. + +You can run the command inside a Git repo directory with no argument, or with one or more repo paths or URLs. For example, from Warp: + +{/* TODO: Update warp-internal to warp once the repo is open-sourced */} +```bash +# File paths +/create-environment ./warp-internal ./warp-server + +# owner/repo +/create-environment warpdotdev/warp-internal warpdotdev/warp-server + +# GitHub URLs +/create-environment https://github.com/warpdotdev/warp-internal.git +``` + +The guided flow will: + +1. Detect the repositories you want the agent to work with and identify languages, frameworks, and tools +2. Look for an existing Dockerfile, recommend an official base image, or help build a custom image (if needed) +3. Suggest setup commands based on your scripts and package managers +4. Create the environment through the CLI and return an environment ID + +This produces a ready-to-use environment that can immediately be connected to [Slack](/agent-platform/cloud-agents/integrations/slack/) or [Linear](/agent-platform/cloud-agents/integrations/linear/). + +### Option 2: Create an environment with the CLI + +If you already know how you want to configure your environment, you can create it directly with the CLI. + +**Use this approach when:** + +* You already have a custom Docker image +* You want full control over repos and setup commands +* You’re scripting or automating environment creation + +From Warp: + +```sh +oz environment create \ + --name <name> \ + --docker-image <image> \ + --repo <owner/repo> \ + --repo <owner/repo> \ + --setup-command "<command1>" \ + --setup-command "<command2>" \ + --description "Optional description" +``` + +Key flags: + +* `--name` (`-n`) – human-readable label for the environment. +* `--docker-image` (`-d`) – image name on Docker Hub. If not specified, you'll be prompted to select from available images (see `oz environment image list`). +* `--repo` (`-r`) – can be repeated for each repo. +* `--setup-command` (`-c`) – can be repeated; commands run in the order provided. +* `--description` – optional description (max 240 characters). + +You can inspect existing environments with `oz environment list`. + +To delete an environment, use `oz environment delete <ID>`. Add `--force` to skip confirmation checks for environments used by integrations. + +For more details about environment configuration, see the [Slack](/agent-platform/cloud-agents/integrations/slack/) and [Linear](/agent-platform/cloud-agents/integrations/linear/) articles. + +#### Example environments + +<table><thead><tr><th width="168.47265625">Project type</th><th width="185.828125">Docker image</th><th>Repos</th><th>Example setup commands</th></tr></thead><tbody><tr><td>Web dev project</td><td><code>node:20-bullseye</code></td><td>your-org/frontend-react<br /><br />your-org/backend-api</td><td><p><code>npm install -g pnpm</code></p><p><br /><code>cd frontend-react && pnpm install</code></p><p><br /><code>cd backend-api && pnpm install</code></p></td></tr><tr><td>Python project</td><td>Custom image based on <code>python:3.11</code></td><td>your-org/cool_python_project</td><td><code>cd cool_python_project && pip install -r requirements.txt</code></td></tr></tbody></table> + +--- + +## Step 2: Authorizing GitHub + +Warp needs GitHub access so agents can clone your repositories and, when permitted, write code and open pull requests. + +#### How GitHub Authorization works + +When you create an environment or integration, Warp will prompt you to: + +* Install or update the Warp GitHub app +* Grant access to the repositories in your environment + +This authorization enables agents to clone repositories into the environment, create branches and commits, and open pull requests. + +**Public vs private repos** + +* **Public repos:** Agents can read code without authorization, but cannot write or open PRs. +* **Private repos:** The Warp GitHub App must have access and the triggering user must have write permissions. + +#### Ongoing permissions + +Depending on how the GitHub app is installed in your organization: + +* You may need to grant access to new repositories over time +* An organization admin may need to update the app's permissions + +You typically only need to handle this once per team, unless your repo access changes. + +#### Team-level GitHub authorization + +For automated workflows that use a [team API key](/reference/cli/api-keys/) (CI/CD pipelines, scheduled agents, SDK-triggered runs), you can configure team GitHub authorization so the agent authenticates with the Oz by Warp GitHub App instead of an individual's personal token. + +This requires a Warp team admin to enable the GitHub organization in the Admin Panel (**Settings** > **Admin Panel** > **Platform**). Once configured, tasks initiated with a team API key can clone repos and open pull requests using the GitHub App installation token. + +For full setup instructions, see [Team GitHub authorization](/agent-platform/cloud-agents/team-access-billing-and-identity/#team-github-authorization). + +:::note +**Using API keys:** Personal API keys authenticate as you, so the agent runs with your GitHub permissions and code changes are attributed to your account. Team API keys with [team GitHub authorization](/agent-platform/cloud-agents/team-access-billing-and-identity/#team-github-authorization) configured use the GitHub App token instead. +::: + +--- + +## Step 3: Setting up an integration + +Once you have set up at least one environment, you can create integrations that connect it to Slack or Linear. + +:::note +For easier setup, use the [Oz web app](https://oz.warp.dev) to configure integrations with a guided flow. +::: + +Alternatively, use the CLI where `<ENV_ID>` is your environment ID: + +```bash +oz integration create slack --environment <ENV_ID> +# or +oz integration create linear --environment <ENV_ID> +``` + +:::note +If you omit `--environment`, the CLI will show a list of environments and prompt you to choose one. +::: + +The CLI then: + +1. Links the integration to your Warp team and environment. +2. Opens a browser flow to install the Oz app into your Slack workspace or Linear workspace. +3. Generates an **integration ID** you can later list or delete. + +**Additional `integration create` flags:** + +* `--prompt` — custom instructions applied to all runs for this integration. +* `--mcp <SPEC>` — attach MCP servers (inline JSON, file path, or UUID). Can be repeated. +* `--model <MODEL_ID>` — override the default model. +* `--host <WORKER_ID>` — run on a specific self-hosted worker. +* `--file <PATH>` (`-f`) — load configuration from a YAML or JSON file. + +**Example with a custom prompt:** + +```bash +oz integration create slack \ + --environment <ENV_ID> \ + --prompt "Always prefix PR titles with [WARP-AGENT] and add detailed test steps." +``` + +### Updating an integration + +You can modify an existing integration using `oz integration update`: + +```bash +oz integration update slack \ + --environment <ENV_ID> \ + --prompt "Updated instructions for the integration." +``` + +**Update-specific flags:** + +* `--environment <ID>` — change the environment. +* `--remove-environment` — remove the environment from the integration. +* `--prompt` — update the custom instructions. +* `--mcp <SPEC>` — add MCP servers to the integration. +* `--remove-mcp <SERVER_NAME>` — remove an MCP server by name. +* `--model <MODEL_ID>` — update the default model. +* `--host <WORKER_ID>` — update the execution host. + +:::note +For more details, see the dedicated pages for [Slack](/agent-platform/cloud-agents/integrations/slack/) and [Linear](/agent-platform/cloud-agents/integrations/linear/) integrations. +::: + +## How are environments used at runtime? + +When you trigger an agent from Slack or Linear, Warp follows a consistent, repeatable execution process using your environment. + +At a high level, each run works like this: + +1. **Warp receives the trigger**\ + Warp captures the message content (for example, a Slack thread or Linear issue), along with any linked context. +2. **Warp creates an execution container**\ + Warp spins up a fresh container from the Docker image defined in your environment. +3. **Repositories are cloned**\ + The GitHub repositories associated with the environment are cloned into the container. +4. **Setup commands are run**\ + Any setup commands you configured, like installing dependencies, are executed. +5. **The agent workflow runs**\ + The agent executes the task using the provided context, tools, and permissions. +6. **Results are posted back**\ + Progress updates, summaries, and results are posted back to Slack or Linear. +7. **The container is destroyed**\ + After the run completes, the container is torn down. Each run starts from a clean, isolated environment. + +## Next steps + +You now have everything needed to trigger agents from your team's tools. From here, you can: + +* Add or adjust setup commands +* Switch to a custom Docker image +* Include additional repositories +* Add custom prompts for consistent agent behavior +* Create separate environments for different workflows or teams + +**Additional reading** + +* [Cloud Agents Overview](/agent-platform/cloud-agents/overview/) +* [Oz Platform](/agent-platform/cloud-agents/platform/) +* [Slack](/agent-platform/cloud-agents/integrations/slack/), [Linear](/agent-platform/cloud-agents/integrations/linear/), and [GitHub Actions](/agent-platform/cloud-agents/integrations/github-actions/) integrations +* [Troubleshooting](/reference/cli/troubleshooting/) diff --git a/src/content/docs/reference/cli/mcp-servers.mdx b/src/content/docs/reference/cli/mcp-servers.mdx new file mode 100644 index 0000000..81dc72a --- /dev/null +++ b/src/content/docs/reference/cli/mcp-servers.mdx @@ -0,0 +1,109 @@ +--- +title: MCP servers +description: >- + Connect agents to external tools like GitHub, Linear, and Sentry by passing + MCP servers to the --mcp flag as a UUID, inline JSON, or file path. +--- + +MCP servers connect agents to external systems like GitHub, Linear, or Sentry. To use a [Model Context Protocol (MCP)](/agent-platform/capabilities/mcp/) server from the CLI, use the `--mcp` flag with `oz agent run` or `oz agent run-cloud`. + +For a conceptual overview of MCP with cloud agents — including configuration schema, full agent config examples, and limitations — see [MCP Servers](/agent-platform/cloud-agents/mcp/) in the Cloud Agents docs. + +--- + +## Using the `--mcp` flag + +The `--mcp` flag accepts three formats: + +* **UUID** — reference a Warp-shared MCP server by its UUID (find UUIDs with `oz mcp list`) +* **Inline JSON** — pass a full MCP JSON configuration directly as a string +* **File path** — path to a JSON file containing the MCP configuration + +You can repeat `--mcp` to include multiple servers. + +### Passing MCP servers by UUID + +1. Locate the MCP server UUID using `oz mcp list`. This command lists all MCP servers configured in your Warp account, including team-shared ones: + +```sh +$ oz mcp list ++--------------------------------------+--------+ +| UUID | Name | ++===============================================+ +| 1deb1b14-b6e5-4996-ae99-233b7555d2d0 | github | +|--------------------------------------+--------| +| 65450c32-9eb1-4c57-8804-0861737acbc4 | linear | +|--------------------------------------+--------| +| d94ade64-0e73-47a6-b3ee-14e5afec3d90 | Sentry | ++--------------------------------------+--------+ +``` + + Alternatively, copy the UUID from Warp in **Settings** > **Agents** > **MCP servers**. + +![MCP servers page, showing a server with its UUID](../../../../assets/reference/mcp-server-id.png) + +2. Pass the UUID to `--mcp`: + +```sh +$ oz agent run --mcp "1deb1b14-b6e5-4996-ae99-233b7555d2d0" --prompt "who last updated the README?" +``` + +### Passing MCP servers as inline JSON or a file + +You can pass MCP configuration inline or via a file: + +```sh +# Inline JSON +$ oz agent run --mcp '{"github": {"url": "https://api.githubcopilot.com/mcp/"}}' --prompt "list open issues" + +# From a file +$ oz agent run --mcp ./my-mcp-config.json --prompt "list open issues" +``` + +The file must contain a valid MCP JSON object. For example: + +```json +{ + "github": { + "url": "https://api.githubcopilot.com/mcp/" + }, + "sentry": { + "command": "npx", + "args": ["-y", "mcp-remote@latest", "https://mcp.sentry.dev/mcp"] + } +} +``` + +### Combining multiple servers + +Pass `--mcp` multiple times to combine UUID references, inline JSON, and file-based configs in a single run: + +```sh +$ oz agent run \ + --mcp "1deb1b14-b6e5-4996-ae99-233b7555d2d0" \ + --mcp '{"sentry": {"url": "https://mcp.sentry.dev/sse"}}' \ + --prompt "open a PR that fixes the top Sentry error" +``` + +--- + +## Environment variables on remote machines + +Warp syncs MCP server configuration between machines logged in with your Warp account, but **does not** sync the environment variables used in that configuration. When running on a remote machine, set any required secrets manually before running the agent: + +```sh +export MY_MCP_SERVER_ACCESS_TOKEN="..." +$ oz agent run --mcp "904a8936-fa82-4571-b1d6-166c26197981" --prompt "use my MCP server to check for errors" +``` + +:::note +For cloud agent workflows, use [Oz-managed secrets](/agent-platform/cloud-agents/secrets/) to store and inject credentials safely — secrets are stored in the cloud and referenced by name in your config. For local runs, a secrets manager CLI such as [`op`](https://developer.1password.com/docs/cli/get-started/), [`pass`](https://www.passwordstore.org/), or [`gcloud secrets versions access`](https://cloud.google.com/secret-manager/docs/create-secret-quickstart#secretmanager-quickstart-gcloud) can fetch secrets on remote hosts without exposing them in your shell history. +::: + +--- + +## Learn more + +* [MCP Servers (cloud agents)](/agent-platform/cloud-agents/mcp/) — configuration schema, full agent config file examples, and cloud agent limitations +* [Model Context Protocol (MCP)](/agent-platform/capabilities/mcp/) — configuring MCP servers in Warp for local agents +* [Secrets](/agent-platform/cloud-agents/secrets/) — store credentials in Warp so agents can access them at run time without exposing them in config files diff --git a/src/content/docs/reference/cli/quickstart.mdx b/src/content/docs/reference/cli/quickstart.mdx new file mode 100644 index 0000000..608cb81 --- /dev/null +++ b/src/content/docs/reference/cli/quickstart.mdx @@ -0,0 +1,92 @@ +--- +title: Quick Start +description: >- + Set up and run your first cloud agent via the Oz CLI in less than 5 minutes. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +This guide walks you through the essentials to get up and running with the Oz CLI in less than 5 minutes: installing the CLI, authenticating, running your first local agent, and optionally connecting MCP servers to give the agent access to external tools. + +Watch this short demo of the Oz CLI workflow: +<VideoEmbed url="https://youtu.be/WpcChBNDCXQ" /> + +## 1. Install the CLI + +If you already have the [Warp desktop app installed](/getting-started/quickstart/installation-and-setup/), the **CLI is included** and available in Warp. + +If not, see [Installing the CLI](/reference/cli/#installing-the-cli) for installation options for all platforms. + +## 2. Authenticate + +For local development and first-time setup, authenticate interactively using the `oz login` command. + +**For example, on macOS:** + +```sh +oz login +``` + +This command prints a sign-in URL in your terminal. Open the URL in your browser to login to Warp. Your credentials will be stored securely for future CLI use. + +Interactive login works on both **local** and **remote** machines, and does not require API keys. + +:::note +**Running in CI or a headless environment?** Use an API key instead of `oz login`. Export it before running any `oz` command: + +```sh +export WARP_API_KEY="wk-..." +``` + +In the Warp app, create an API key in **Settings** > **Cloud platform** > **Oz Cloud API Keys**. See [API Keys](/reference/cli/api-keys/) for guidance on personal vs. team keys and security best practices. +::: + +## 3. Run an agent + +From any directory, run: + +```sh +oz agent run --prompt "summarize this directory" +``` + +This uses the default agent profile, loads any available MCP servers, and executes the run locally. The output appears directly in your terminal. + +What happens: + +* The agent runs locally in your current working directory. +* The session is tracked on Warp's backend for observability and collaboration. +* The agent autonomously executes commands and streams output to your terminal. + +## 4. Run a cloud agent (optional) + +Cloud agents run in a remote environment with your repositories cloned and dependencies installed, making them useful for tasks that need full codebase access. + +If you haven't already created an environment, run `/create-environment` in Warp or follow the [Cloud Agents Quickstart](/agent-platform/cloud-agents/quickstart/). Then run the following command: + +```sh +oz agent run-cloud --environment <ENV_ID> --prompt "Scan this repo for outdated dependencies" +``` + +Replace `<ENV_ID>` with your environment ID, which you can find by running `oz environment list` on the Oz CLI. + +## 5. Add MCP context (optional) + +You can connect MCP servers to give the agent access to external tools like GitHub or Linear. Pass MCP configuration inline or from a file using the `--mcp` flag: + +```sh +oz agent run --mcp '{"github": {"url": "https://api.githubcopilot.com/mcp/"}}' --prompt "Open a pull request that fixes TODOs in this repo" +``` + +See [MCP Servers](/reference/cli/mcp-servers/) for all supported formats, including UUID references and multi-server configurations. + +## Next steps + +Once you've successfully set up and run your agent, explore other configurations and workflows with the Oz CLI: + +* Customize behavior with [agent profiles](/reference/cli/agent-profiles/). +* [Reuse prompts](/reference/cli/warp-drive/) with `--saved-prompt`. +* Connect agents to external systems using [MCP Servers](/reference/cli/mcp-servers/). +* Authenticate with [API keys](/reference/cli/api-keys/) for automated environments or workflows. +* Get up-to-date information about the Oz CLI using the [`oz help` command](/reference/cli/troubleshooting/#getting-help). +* Run agents in CI with the [GitHub Actions quickstart](/agent-platform/cloud-agents/integrations/quickstart-github-actions/). + +Continue reading the [Oz CLI reference](/reference/cli/) to learn how to install the CLI on different platforms, authenticate in different environments, and configure agents for real-world workflows. diff --git a/src/content/docs/reference/cli/skills.mdx b/src/content/docs/reference/cli/skills.mdx new file mode 100644 index 0000000..d98c9e8 --- /dev/null +++ b/src/content/docs/reference/cli/skills.mdx @@ -0,0 +1,60 @@ +--- +title: "Skills (CLI)" +description: >- + Use skills with the Oz CLI to run agents from reusable skill definitions + stored in your repositories. +--- + +[Skills](/agent-platform/capabilities/skills/) are reusable instruction sets that teach agents how to perform specific tasks. Use the `--skill` flag to run an agent from a skill in a repository accessible to your environment. + +## Skill spec format + +The `--skill` flag accepts a skill specification that identifies which skill to use: + +```sh +# Fully qualified (recommended) +oz agent run-cloud -e <ENV_ID> --skill "owner/repo:skill-name" --prompt "deploy to staging" + +# With full path +oz agent run-cloud -e <ENV_ID> --skill "warpdotdev/warp-server:.warp/skills/deploy/SKILL.md" --prompt "deploy to staging" +``` + +Supported formats: + +* `owner/repo:skill-name` — skill by name in a specific repository (recommended) +* `owner/repo:path/to/SKILL.md` — skill by full path in a repository +* `repo:skill-name` — skill by name (only works when the repo is configured in your environment) + +## Using skills with cloud agents + +Skills are particularly useful with cloud agents (`oz agent run-cloud`) because they define reusable workflows that run consistently across environments: + +```sh +# Run a deploy skill from a specific repo +oz agent run-cloud \ + --environment SVhg783GBFQHk1OfdPfFU9 \ + --skill "myorg/backend:.warp/skills/deploy/SKILL.md" \ + --prompt "deploy to staging" + +# Run a code review skill +oz agent run-cloud \ + --environment SVhg783GBFQHk1OfdPfFU9 \ + --skill "myorg/backend:code-review" \ + --prompt "review the latest PR" +``` + +:::note +When you specify a skill, it provides the base instructions for the agent. The `--prompt` adds additional context or parameters for that specific run. +::: + +When you run an agent from a skill, the run `name` is automatically set to the skill name — no need to pass `--name` explicitly. + +## Using skills with local agents + +For local agent runs, skills from your current repository are automatically discovered. You can also explicitly specify a skill: + +```sh +oz agent run --skill "owner/repo:skill-name" --prompt "additional context" +``` + +For more information about creating and managing skills, see [Skills](/agent-platform/capabilities/skills/). diff --git a/src/content/docs/reference/cli/troubleshooting.mdx b/src/content/docs/reference/cli/troubleshooting.mdx new file mode 100644 index 0000000..81658be --- /dev/null +++ b/src/content/docs/reference/cli/troubleshooting.mdx @@ -0,0 +1,184 @@ +--- +title: CLI Troubleshooting +description: >- + Solutions for common Oz CLI errors — including authentication issues, agent + failures, environments, GitHub access, and Docker image issues. +--- + +## Getting help + +The CLI includes built-in documentation for all commands: + +```bash +# See all available commands +oz help + +# Get details on a specific command +oz help agent run + +# Explore MCP-related commands +oz help mcp +``` + +## Common errors + +**Command not found / CLI not installed correctly**\ +Verify your installation path and confirm the CLI version: + +```bash +oz --version +``` + +**Authentication issues** + +* Interactive login: ensure you've completed the browser-based flow with `oz login`. +* API keys: confirm the key is valid, not expired, and exported correctly. + +**Agent or MCP errors**\ +Ensure your agent profile and [MCP servers](/agent-platform/capabilities/mcp/) are configured properly, with correct permissions. See [MCP Servers](/reference/cli/mcp-servers/) and [Agent profiles](/reference/cli/agent-profiles/) for details. + +--- + +## Environments + +#### How do I see what environment my integration is using? + +List your integrations: + +``` +oz integration list +``` + +This shows each integration, its ID, and the environment it’s linked to. Use this to confirm which environment to inspect or update before making changes. + +#### How do I see what’s inside that environment? + +Once you know the environment ID, run: + +``` +oz environment get <ENV_ID> +``` + +This prints the full configuration, including: + +* The **environment ID** (used in other commands) +* The **name** +* The **Docker image** +* Associated **repos** + +This is the most reliable way to verify what the agent will see when it runs. + +#### How do I add or remove repos and setup commands? + +Use `oz environment` update. You can modify environments incrementally without recreating them. + +**Add a repo:** + +``` +oz environment update <ENV_ID> --repo owner/repo +``` + +**Remove a repo:** + +``` +oz environment update <ENV_ID> --remove-repo owner/repo +``` + +**Add a setup command:** + +``` +oz environment update <ENV_ID> --setup-command "your command" +``` + +**Remove a setup command (must match exactly):** + +``` +oz environment update <ENV_ID> --remove-setup-command "exact command" +``` + +Notes: + +* Warp may prompt you to adjust GitHub app permissions when adding repos. +* Setup commands run in the order they are defined. + +#### **How do I delete an environment?** + +If an environment is no longer needed: + +``` +oz environment delete <ID> +``` + +Add `--force` to skip confirmation checks for environments used by integrations. + +Only do this once you've confirmed no active integrations are relying on that environment. If an integration points to a deleted environment, requests from Slack/Linear will fail until you create a new integration with a valid environment. + +### Integrations + +#### **How do I figure out what environment my integration is using?** + +List your integrations: + +``` +oz integration list +``` + +This shows each integration, its ID, and the environment it’s attached to. Use this when you’re unsure which environment to update or delete. + +#### **I created a new environment, but don’t see it when running oz integration create** + +Check: + +1. Environment exists and is healthy: `oz environment list` +2. You’re on the correct Warp team. Make sure your local CLI is logged into the same team where the environment was created. + 1. If both look correct and the environment still doesn’t appear, recreate it and confirm there were no errors during creation. + +## GitHub & repo access issues + +#### **I’m being asked to authorize GitHub when creating/using an environment** + +This happens when: + +* You add a repo that Warp doesn’t have access to yet, or +* You personally haven’t granted the Warp GitHub app permissions for that repo. + +Follow the GitHub popup flow to install/adjust the Warp GitHub app. + +#### **The agent can’t open PRs or push changes to my repo** + +Check the following: + +1. **Repo is part of your environment**. + 1. Make sure the repo is listed in: `oz environment get <id>` +2. **Warp GitHub app has access to that repo** + 1. In GitHub’s settings, confirm the Warp app is installed and that the repo is selected. +3. **You have write access** + 1. The agent inherits your GitHub permissions. If you only have read access, Warp can’t open PRs or push branches on your behalf. + +### Docker image & environment failures + +#### **I see errors like “pull access denied” or “repository does not exist”** + +Check: + +1. The Docker image name and tag are correct. +2. The image is public on Docker Hub. +3. You can pull it locally: `docker pull <image_name>` + +If local docker pull fails, fix the image visibility/name first, then recreate or update the environment with a working image. + +#### **The agent can’t find tools or runtimes inside the environment** + +This usually means the Docker image is missing required dependencies. Fix by either: + +* Updating the Dockerfile used to build the image, then pushing a new version to Docker Hub and updating the environment with the new image, or +* Adding additional setup commands to install the missing tools: `oz environment update --setup-command "apt-get update && apt-get install -y "` + +#### **I see "VM failed before the agent could run. This is likely an issue with your Docker image"** + +This typically means your Docker image uses musl libc instead of glibc. Alpine Linux and other musl-based images are not compatible with the agent runtime. + +Fix: + +* Switch to a glibc-based image such as Debian, Ubuntu, or the default (non-Alpine) variants of official Docker Hub images (e.g. `node`, `python`, `rust`). +* If you're using an Alpine variant like `node:20-alpine`, replace it with the default tag (e.g. `node:20`). diff --git a/src/content/docs/reference/cli/warp-drive.mdx b/src/content/docs/reference/cli/warp-drive.mdx new file mode 100644 index 0000000..fc7d3ce --- /dev/null +++ b/src/content/docs/reference/cli/warp-drive.mdx @@ -0,0 +1,38 @@ +--- +title: Warp Drive context +description: >- + Use saved prompts, notebooks, workflows, and rules from Warp Drive as + context in CLI agent commands. +--- + +## Reusing saved prompts + +When you find prompts that work well, save them in [Warp Drive](/knowledge-and-collaboration/warp-drive/) to reuse across sessions, share with teammates, and integrate into automated workflows. For more information, see [Prompts](/knowledge-and-collaboration/warp-drive/prompts/). + +To reuse a saved prompt, find its ID. The ID is the last segment of its Warp Drive sharing link. + +For example, in the URL: + +``` +https://warp.dev/drive/prompt/Fix-compiler-error-sgNpbUgDkmp2IImUVDc8kR +``` + +...the ID is `sgNpbUgDkmp2IImUVDc8kR`. + +Then pass the ID using the `--saved-prompt` flag: + +```bash +$ oz agent run --saved-prompt sgNpbUgDkmp2IImUVDc8kR +``` + +## Referencing Warp Drive objects as context + +Use `<workflow:id>`, `<notebook:id>`, or `<rule:id>` in prompts to attach [Warp Drive objects](/knowledge-and-collaboration/warp-drive/) and [rules](/agent-platform/capabilities/rules/) as context for the agent. + +:::note +**Tip:** Use the [@ context menu](/agent-platform/local-agents/agent-context/using-to-add-context/) in Warp to construct a prompt with the right references, then copy it into your CLI command. +::: + +```bash +$ oz agent run --prompt "Follow the instructions in <notebook:gq1CMAUWLtaL1CpEoTDQ3y>" +``` diff --git a/src/content/docs/reference/index.mdx b/src/content/docs/reference/index.mdx new file mode 100644 index 0000000..360872b --- /dev/null +++ b/src/content/docs/reference/index.mdx @@ -0,0 +1,25 @@ +--- +title: Technical reference +description: >- + Technical reference documentation for the Oz CLI, API, and SDK. +--- + +This section covers the programmatic interfaces for running and managing Oz agents in CI pipelines, scripts, backend services, and custom tooling. + +## CLI + +The [Oz CLI](/reference/cli/) lets you run and configure agents from any environment — locally, in CI pipelines, or on remote machines. + +- [API Keys](/reference/cli/api-keys/) - Create and manage API keys to authenticate the Oz CLI without human interaction, ideal for CI pipelines, headless servers, and containers. +- [Agent Profiles](/reference/cli/agent-profiles/) - Use agent profiles to control what the agent can access, how it behaves, and where it can act, including file access, command execution, and MCP server usage. +- [MCP Servers](/reference/cli/mcp-servers/) - Pass MCP server configuration to agent runs using the `--mcp` flag, by UUID, inline JSON, or file path. +- [Skills](/reference/cli/skills/) - Run agents from reusable instruction sets stored in your repositories using the `--skill` flag. +- [Warp Drive Context](/reference/cli/warp-drive/) - Reference saved prompts, notebooks, workflows, and rules from Warp Drive directly in CLI agent commands. +- [Integration Setup](/reference/cli/integration-setup/) - Configure environments and connect external tools like Slack and Linear so you can trigger Oz agents from outside the terminal. +- [Troubleshooting](/reference/cli/troubleshooting/) - Find solutions to common CLI errors, including authentication issues, agent failures, environment problems, and Docker image issues. + +## API & SDK + +The [Oz API](/reference/api-and-sdk/) lets you create and monitor cloud agent runs over HTTP. Official SDKs for [Python](https://github.com/warpdotdev/oz-sdk-python) and [TypeScript](https://github.com/warpdotdev/oz-sdk-typescript) provide typed clients with built-in retries and error handling. + +- [Demo: Sentry monitoring with SDK](/reference/api-and-sdk/demo-sentry-monitoring-with-sdk/) - example integration diff --git a/src/content/docs/support-and-community/community/contributing.mdx b/src/content/docs/support-and-community/community/contributing.mdx new file mode 100644 index 0000000..819ff68 --- /dev/null +++ b/src/content/docs/support-and-community/community/contributing.mdx @@ -0,0 +1,43 @@ +--- +title: Contributing to Warp +description: >- + Contribute to Warp's open source client by filing issues, opening pull + requests, building themes, sharing workflows, and publishing Warp Drive + objects to the community. +--- + +Warp's client is open source under [AGPL v3](https://github.com/warpdotdev/warp/blob/master/LICENSE) at [`warpdotdev/warp`](https://github.com/warpdotdev/warp), and there's room for every kind of contribution — from a one-line bug report to a full feature PR, a new theme, or a workflow that ships to every Warp user. For the full code contribution flow, see [`CONTRIBUTING.md`](https://github.com/warpdotdev/warp/blob/master/CONTRIBUTING.md). + +## Ways you can contribute + +* **Report a bug or request a feature** - [File an issue](https://github.com/warpdotdev/warp/issues/new/choose) in [`warpdotdev/warp`](https://github.com/warpdotdev/warp), or [explore existing issues](https://github.com/warpdotdev/warp/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc) to comment on or upvote ones that matter to you. Clear reproductions and upvotes help Warp prioritize. +* **Contribute code** - Claim any issue labeled `ready-to-spec` or `ready-to-implement`, then open a spec or code PR. [`CONTRIBUTING.md`](https://github.com/warpdotdev/warp/blob/master/CONTRIBUTING.md) covers the spec format, tests, `./script/presubmit`, and the PR template. +* **Build a theme** - Submit a new color scheme or improve an existing one at [`warpdotdev/themes`](https://github.com/warpdotdev/themes). +* **Share a workflow** - Add reusable command patterns to [`warpdotdev/workflows`](https://github.com/warpdotdev/workflows). Merged workflows ship to every Warp user. +* **Publish Warp Drive objects** - Share Workflows, Notebooks, Rules, and Prompts publicly from [Warp Drive](/knowledge-and-collaboration/warp-drive/). +* **Find an issue to pick up** - Browse [`build.warp.dev`](https://build.warp.dev), a live dashboard of the work Warp's agents are tackling across `warpdotdev/warp`. Use it to spot gaps, avoid duplicate work, and surface issues that haven't been claimed yet. +* **Help others in the community** - Answer questions in the [Warp community Slack](https://go.warp.dev/join-preview) or [Discord](https://discord.com/invite/warpdotdev), and join conversations in [GitHub Discussions](https://github.com/warpdotdev/warp/discussions). + +## Send feedback and bug reports + +The fastest way to file a bug or feature request is the [`/feedback`](/support-and-community/troubleshooting-and-support/sending-us-feedback/#using-feedback-in-warp) slash command inside Warp. It drafts and files a GitHub issue without leaving the terminal. + +Other channels: + +* File an issue directly in [`warpdotdev/warp`](https://github.com/warpdotdev/warp/issues/new/choose). +* Press `⌘+Shift+F` (macOS) or `Ctrl+Shift+F` (Windows/Linux) to open the in-app feedback dialog. On macOS, you can also use the **Send Feedback** option in Warp's Help menu. +* Email [privacy@warp.dev](mailto:privacy@warp.dev) for privacy questions. + +For logs, crash reports, CPU samples, and AI debugging IDs, see [Sending feedback and logs](/support-and-community/troubleshooting-and-support/sending-us-feedback/). + +## Reporting security issues + +:::danger +Do not file public issues for security vulnerabilities. +::: + +Email [security@warp.dev](mailto:security@warp.dev) with reproduction steps, impact, and any proof of concept. We'll acknowledge receipt and coordinate a fix and disclosure. Full guidance is in [`CONTRIBUTING.md`](https://github.com/warpdotdev/warp/blob/master/CONTRIBUTING.md#reporting-security-issues). + +## Code of conduct + +Warp's open source repositories follow the [Contributor Covenant](https://www.contributor-covenant.org/) v2.1. Read the [full text](https://github.com/warpdotdev/warp/blob/master/CODE_OF_CONDUCT.md), or report violations to [warp-coc@warp.dev](mailto:warp-coc@warp.dev). diff --git a/src/content/docs/support-and-community/community/open-source-licenses.mdx b/src/content/docs/support-and-community/community/open-source-licenses.mdx new file mode 100644 index 0000000..e075f76 --- /dev/null +++ b/src/content/docs/support-and-community/community/open-source-licenses.mdx @@ -0,0 +1,466 @@ +--- +title: Open source licenses +description: >- + These are the third-party libraries that Warp depends on. +--- + +This page lists the **third-party** libraries that Warp's client depends on. For Warp's own client source code (open source under AGPL v3), see [Contributing to Warp](/support-and-community/community/contributing/) and [`warpdotdev/warp`](https://github.com/warpdotdev/warp). + +## Cargo based licenses + +Repositories are by default GitHub if not otherwise specified. + +| Name | License | Repository | +| ----------------------------- | --------------------------------------------------- | -----------------------------------------------------: | +| addr2line | Apache-2.0 OR MIT | gimli-rs/addr2line | +| adler | 0BSD OR Apache-2.0 OR MIT | jonas-schievink/adler.git | +| adler32 | Zlib | remram44/adler32-rs | +| aho-corasick | MIT OR Unlicense | BurntSushi/aho-corasick | +| analytics | MIT | | +| ansi\_term | MIT | | +| anyhow | Apache-2.0 OR MIT | dtolnay/anyhow | +| arrayref | BSD-2-Clause | droundy/arrayref | +| arrayvec | Apache-2.0 OR MIT | bluss/arrayvec | +| as-slice | Apache-2.0 OR MIT | japaric/as-slice | +| ascii | Apache-2.0 OR MIT | tomprogrammer/rust-ascii | +| async-broadcast | Apache-2.0 OR MIT | smol-rs/async-broadcast | +| async-channel | Apache-2.0 OR MIT | smol-rs/async-channel | +| async-executor | Apache-2.0 OR MIT | stjepang/async-executor | +| async-fs | Apache-2.0 OR MIT | stjepang/async-fs | +| async-io | Apache-2.0 OR MIT | smol-rs/async-io | +| async-lock | Apache-2.0 OR MIT | smol-rs/async-lock | +| async-net | Apache-2.0 OR MIT | smol-rs/async-net | +| async-process | Apache-2.0 OR MIT | smol-rs/async-process | +| async-task | Apache-2.0 OR MIT | stjepang/async-task | +| async-task | Apache-2.0 OR MIT | stjepang/async-task | +| atomic-waker | Apache-2.0 OR MIT | stjepang/atomic-waker | +| atty | MIT | softprops/atty | +| autocfg | Apache-2.0 OR MIT | cuviper/autocfg | +| backtrace | Apache-2.0 OR MIT | rust-lang/backtrace-rs | +| base64 | Apache-2.0 OR MIT | marshallpierce/rust-base64 | +| base64 | Apache-2.0 OR MIT | marshallpierce/rust-base64 | +| bindgen | BSD-3-Clause | rust-lang/rust-bindgen | +| bitflags | Apache-2.0 OR MIT | bitflags/bitflags | +| block | MIT | SSheldon/rust-block | +| blocking | Apache-2.0 OR MIT | stjepang/blocking | +| bounded-vec-deque | BSD-3-Clause OR GPL-3.0+ | | +| bumpalo | Apache-2.0 OR MIT | fitzgen/bumpalo | +| bytemuck | Apache-2.0 OR MIT OR Zlib | Lokathor/bytemuck | +| byteorder | MIT OR Unlicense | BurntSushi/byteorder | +| bytes | MIT | tokio-rs/bytes | +| bytes | MIT | tokio-rs/bytes | +| cache-padded | Apache-2.0 OR MIT | stjepang/cache-padded | +| cc | Apache-2.0 OR MIT | alexcrichton/cc-rs | +| cexpr | Apache-2.0 OR MIT | jethrogb/rust-cexpr | +| cfg-if | Apache-2.0 OR MIT | alexcrichton/cfg-if | +| cfg-if | Apache-2.0 OR MIT | alexcrichton/cfg-if | +| chrono | Apache-2.0 OR MIT | chronotope/chrono | +| clang-sys | Apache-2.0 | KyleMayes/clang-sys | +| clap | MIT | clap-rs/clap | +| cloudabi | BSD-2-Clause | nuxinl/cloudabi | +| cmake | Apache-2.0 OR MIT | alexcrichton/cmake-rs | +| cocoa | Apache-2.0 OR MIT | servo/core-foundation-rs | +| cocoa-foundation | Apache-2.0 OR MIT | servo/core-foundation-rs | +| color\_quant | MIT | image-rs/color\_quant.git | +| combine | MIT | Marwes/combine | +| concurrent-queue | Apache-2.0 OR MIT | stjepang/concurrent-queue | +| const\_format | Zlib | rodrimati1992/const\_format\_crates/ | +| const\_format\_proc\_macros | Zlib | rodrimati1992/const\_format\_crates/ | +| convert\_case | MIT | rutrum/convert-case | +| core-foundation | Apache-2.0 OR MIT | servo/core-foundation-rs | +| core-foundation | Apache-2.0 OR MIT | servo/core-foundation-rs | +| core-foundation | Apache-2.0 OR MIT | servo/core-foundation-rs | +| core-foundation-sys | Apache-2.0 OR MIT | servo/core-foundation-rs | +| core-foundation-sys | Apache-2.0 OR MIT | servo/core-foundation-rs | +| core-foundation-sys | Apache-2.0 OR MIT | servo/core-foundation-rs | +| core-graphics | Apache-2.0 OR MIT | servo/core-foundation-rs | +| core-graphics | Apache-2.0 OR MIT | servo/core-foundation-rs | +| core-graphics-types | Apache-2.0 OR MIT | servo/core-foundation-rs | +| core-graphics-types | Apache-2.0 OR MIT | servo/core-foundation-rs | +| core-text | Apache-2.0 OR MIT | servo/core-foundation-rs | +| crc32fast | Apache-2.0 OR MIT | srijs/rust-crc32fast | +| crossbeam-channel | Apache-2.0 OR MIT | crossbeam-rs/crossbeam | +| crossbeam-deque | Apache-2.0 OR MIT | crossbeam-rs/crossbeam | +| crossbeam-epoch | Apache-2.0 OR MIT | crossbeam-rs/crossbeam | +| crossbeam-utils | Apache-2.0 OR MIT | crossbeam-rs/crossbeam | +| ctor | Apache-2.0 OR MIT | mmastrac/rust-ctor | +| darling | MIT | TedDriggs/darling | +| darling\_core | MIT | TedDriggs/darling | +| darling\_macro | MIT | TedDriggs/darling | +| dashmap | MIT | xacrimon/dashmap | +| data-url | Apache-2.0 OR MIT | servo/rust-url | +| debugid | Apache-2.0 | getsentry/rust-debugid | +| deflate | Apache-2.0 OR MIT | image-rs/deflate-rs | +| derive-new | MIT | nrc/derive-new | +| diesel | Apache-2.0 OR MIT | diesel-rs/diesel | +| diesel\_derives | Apache-2.0 OR MIT | diesel-rs/diesel/tree/master/diesel\_derives | +| diesel\_migrations | Apache-2.0 OR MIT | | +| dirs | Apache-2.0 OR MIT | soc/dirs-rs | +| dirs-next | Apache-2.0 OR MIT | xdg-rs/dirs | +| dirs-sys | Apache-2.0 OR MIT | dirs-dev/dirs-sys-rs | +| dirs-sys-next | Apache-2.0 OR MIT | xdg-rs/dirs/tree/master/dirs-sys | +| doc-comment | MIT | GuillaumeGomez/doc-comment | +| dtoa | Apache-2.0 OR MIT | dtolnay/dtoa | +| dunce | CC0-1.0 | | +| dwrote | MPL-2.0 | servo/dwrote-rs | +| easy-parallel | Apache-2.0 OR MIT | stjepang/easy-parallel | +| either | Apache-2.0 OR MIT | bluss/either | +| embed\_plist | Apache-2.0 OR MIT | nvzqz/embed-plist-rs | +| enclose | MIT | clucompany/Enclose.git | +| encoding\_rs | Apache-2.0 OR MIT | hsivonen/encoding\_rs | +| env\_logger | Apache-2.0 OR MIT | env-logger-rs/env\_logger/ | +| event-listener | Apache-2.0 OR MIT | stjepang/event-listener | +| expat-sys | MIT | servo/libexpat/ | +| failure | Apache-2.0 OR MIT | rust-lang-nursery/failure | +| failure\_derive | Apache-2.0 OR MIT | rust-lang-nursery/failure | +| fastrand | Apache-2.0 OR MIT | smol-rs/fastrand | +| filetime | Apache-2.0 OR MIT | alexcrichton/filetime | +| flate2 | Apache-2.0 OR MIT | rust-lang/flate2-rs | +| float-cmp | MIT | mikedilger/float-cmp | +| float-ord | Apache-2.0 OR MIT | notriddle/rust-float-ord | +| fnv | Apache-2.0 OR MIT | servo/rust-fnv | +| font-kit | Apache-2.0 OR MIT | servo/font-kit | +| fontdb | MIT | RazrFalcon/fontdb | +| foreign-types | Apache-2.0 OR MIT | sfackler/foreign-types | +| foreign-types-shared | Apache-2.0 OR MIT | sfackler/foreign-types | +| form\_urlencoded | Apache-2.0 OR MIT | servo/rust-url | +| freetype | Apache-2.0 OR MIT | servo/rust-freetype | +| freetype-sys | MIT | PistonDevelopers/freetype-sys.git | +| fs\_extra | MIT | webdesus/fs\_extra | +| fsevent | MIT | octplane/fsevent-rust | +| fsevent-sys | MIT | octplane/fsevent-rust/tree/master/fsevent-sys | +| fsio | Apache-2.0 | sagiegurari/fsio.git | +| fuchsia-zircon | BSD-3-Clause | | +| fuchsia-zircon-sys | BSD-3-Clause | | +| futures | Apache-2.0 OR MIT | rust-lang/futures-rs | +| futures-channel | Apache-2.0 OR MIT | rust-lang/futures-rs | +| futures-core | Apache-2.0 OR MIT | rust-lang/futures-rs | +| futures-executor | Apache-2.0 OR MIT | rust-lang/futures-rs | +| futures-io | Apache-2.0 OR MIT | rust-lang/futures-rs | +| futures-lite | Apache-2.0 OR MIT | smol-rs/futures-lite | +| futures-macro | Apache-2.0 OR MIT | rust-lang/futures-rs | +| futures-sink | Apache-2.0 OR MIT | rust-lang/futures-rs | +| futures-task | Apache-2.0 OR MIT | rust-lang/futures-rs | +| futures-util | Apache-2.0 OR MIT | rust-lang/futures-rs | +| fuzzy-matcher | MIT | lotabout/fuzzy-matcher | +| generic-array | MIT | fizyk20/generic-array.git | +| generic-array | MIT | fizyk20/generic-array.git | +| generic-array | MIT | fizyk20/generic-array.git | +| getrandom | Apache-2.0 OR MIT | rust-random/getrandom | +| getrandom | Apache-2.0 OR MIT | rust-random/getrandom | +| getset | MIT | Hoverbear/getset | +| gif | Apache-2.0 OR MIT | image-rs/image-gif | +| gimli | Apache-2.0 OR MIT | gimli-rs/gimli | +| git2 | Apache-2.0 OR MIT | rust-lang/git2-rs | +| glob | Apache-2.0 OR MIT | rust-lang/glob | +| graphql-introspection-query | Apache-2.0 OR MIT | graphql-rust/graphql-client | +| graphql-parser | Apache-2.0 OR MIT | | +| graphql\_client | Apache-2.0 OR MIT | graphql-rust/graphql-client | +| graphql\_client\_codegen | Apache-2.0 OR MIT | graphql-rust/graphql-client | +| graphql\_query\_derive | Apache-2.0 OR MIT | graphql-rust/graphql-client | +| h2 | MIT | hyperium/h2 | +| h2 | MIT | hyperium/h2 | +| hash32 | Apache-2.0 OR MIT | japaric/hash32 | +| hashbrown | Apache-2.0 OR MIT | rust-lang/hashbrown | +| heapless | Apache-2.0 OR MIT | japaric/heapless | +| heck | Apache-2.0 OR MIT | withoutboats/heck | +| hermit-abi | Apache-2.0 OR MIT | hermitcore/libhermit-rs | +| hex | Apache-2.0 OR MIT | KokaKiwi/rust-hex | +| hostname | MIT | svartalf/hostname | +| http | Apache-2.0 OR MIT | hyperium/http | +| http-body | MIT | hyperium/http-body | +| http-body | MIT | hyperium/http-body | +| httparse | Apache-2.0 OR MIT | seanmonstar/httparse | +| httpdate | Apache-2.0 OR MIT | pyfisch/httpdate | +| httpdate | Apache-2.0 OR MIT | pyfisch/httpdate | +| humantime | Apache-2.0 OR MIT | tailhook/humantime | +| hyper | MIT | hyperium/hyper | +| hyper | MIT | hyperium/hyper | +| hyper-tls | Apache-2.0 OR MIT | hyperium/hyper-tls | +| ident\_case | Apache-2.0 OR MIT | TedDriggs/ident\_case | +| idna | Apache-2.0 OR MIT | servo/rust-url/ | +| image | MIT | image-rs/image | +| indexmap | Apache-2.0 OR MIT | bluss/indexmap | +| inotify | ISC | inotify-rs/inotify | +| inotify-sys | ISC | hannobraun/inotify-sys | +| instant | BSD-3-Clause | sebcrozet/instant | +| iovec | Apache-2.0 OR MIT | carllerche/iovec | +| ipnet | Apache-2.0 OR MIT | krisprice/ipnet | +| itertools | Apache-2.0 OR MIT | rust-itertools/itertools | +| itoa | Apache-2.0 OR MIT | dtolnay/itoa | +| jobserver | Apache-2.0 OR MIT | alexcrichton/jobserver-rs | +| jpeg-decoder | Apache-2.0 OR MIT | image-rs/jpeg-decoder | +| js-sys | Apache-2.0 OR MIT | rustwasm/wasm-bindgen/tree/master/crates/js-sys | +| kernel32-sys | MIT | retep998/winapi-rs | +| kqueue | MIT | | +| kqueue-sys | MIT | | +| kurbo | Apache-2.0 OR MIT | linebender/kurbo | +| lazy\_static | Apache-2.0 OR MIT | rust-lang-nursery/lazy-static.rs | +| lazycell | Apache-2.0 OR MIT | indiv0/lazycell | +| libc | Apache-2.0 OR MIT | rust-lang/libc | +| libgit2-sys | Apache-2.0 OR MIT | rust-lang/git2-rs | +| libloading | ISC | nagisa/rust\_libloading/ | +| libsqlite3-sys | MIT | rusqlite/rusqlite | +| libz-sys | Apache-2.0 OR MIT | rust-lang/libz-sys | +| linked-hash-map | Apache-2.0 OR MIT | contain-rs/linked-hash-map | +| lock\_api | Apache-2.0 OR MIT | Amanieu/parking\_lot | +| lock\_api | Apache-2.0 OR MIT | Amanieu/parking\_lot | +| log | Apache-2.0 OR MIT | rust-lang/log | +| malloc\_buf | MIT | SSheldon/malloc\_buf | +| match\_cfg | Apache-2.0 OR MIT | gnzlbg/match\_cfg | +| matches | MIT | SimonSapin/rust-std-candidates | +| maybe-uninit | Apache-2.0 OR MIT | est31/maybe-uninit | +| memchr | MIT OR Unlicense | BurntSushi/memchr | +| memmap | Apache-2.0 OR MIT | danburkert/memmap-rs | +| memmap2 | Apache-2.0 OR MIT | RazrFalcon/memmap2-rs | +| memoffset | MIT | Gilnaa/memoffset | +| metal | Apache-2.0 OR MIT | gfx-rs/metal-rs | +| migrations\_internals | Apache-2.0 OR MIT | | +| migrations\_macros | Apache-2.0 OR MIT | | +| mime | Apache-2.0 OR MIT | hyperium/mime | +| miniz\_oxide | Apache-2.0 OR MIT OR Zlib | Frommi/miniz\_oxide/tree/master/miniz\_oxide | +| miniz\_oxide | MIT | Frommi/miniz\_oxide/tree/master/miniz\_oxide | +| mio | MIT | tokio-rs/mio | +| mio | MIT | tokio-rs/mio | +| mio-extras | Apache-2.0 OR MIT | dimbleby/mio-extras | +| miow | Apache-2.0 OR MIT | alexcrichton/miow | +| miow | Apache-2.0 OR MIT | yoshuawuyts/miow | +| native-tls | Apache-2.0 OR MIT | sfackler/rust-native-tls | +| net2 | Apache-2.0 OR MIT | deprecrated/net2-rs | +| nix | MIT | nix-rust/nix | +| nom | MIT | Geal/nom | +| notify | CC0-1.0 | notify-rs/notify.git | +| ntapi | Apache-2.0 OR MIT | MSxDOS/ntapi | +| num-derive | Apache-2.0 OR MIT | rust-num/num-derive | +| num-integer | Apache-2.0 OR MIT | rust-num/num-integer | +| num-iter | Apache-2.0 OR MIT | rust-num/num-iter | +| num-rational | Apache-2.0 OR MIT | rust-num/num-rational | +| num-traits | Apache-2.0 OR MIT | rust-num/num-traits | +| num\_cpus | Apache-2.0 OR MIT | seanmonstar/num\_cpus | +| objc | MIT | SSheldon/rust-objc | +| objc-foundation | MIT | SSheldon/rust-objc-foundation | +| objc\_exception | MIT | SSheldon/rust-objc-exception | +| objc\_id | MIT | SSheldon/rust-objc-id | +| object | Apache-2.0 OR MIT | gimli-rs/object | +| once\_cell | Apache-2.0 OR MIT | matklad/once\_cell | +| openssl | Apache-2.0 | sfackler/rust-openssl | +| openssl-probe | Apache-2.0 OR MIT | alexcrichton/openssl-probe | +| openssl-sys | MIT | sfackler/rust-openssl | +| ordered-float | MIT | reem/rust-ordered-float | +| ordered-float | MIT | reem/rust-ordered-float | +| parking | Apache-2.0 OR MIT | stjepang/parking | +| parking\_lot | Apache-2.0 OR MIT | Amanieu/parking\_lot | +| parking\_lot | Apache-2.0 OR MIT | Amanieu/parking\_lot | +| parking\_lot\_core | Apache-2.0 OR MIT | Amanieu/parking\_lot | +| parking\_lot\_core | Apache-2.0 OR MIT | Amanieu/parking\_lot | +| pathfinder\_color | Apache-2.0 OR MIT | servo/pathfinder | +| pathfinder\_geometry | Apache-2.0 OR MIT | servo/pathfinder | +| pathfinder\_simd | Apache-2.0 OR MIT | servo/pathfinder | +| pdqselect | Apache-2.0 OR MIT | | +| peeking\_take\_while | Apache-2.0 OR MIT | fitzgen/peeking\_take\_while | +| percent-encoding | Apache-2.0 OR MIT | servo/rust-url/ | +| permissions | MIT | marcospb19/dotao | +| pest | Apache-2.0 OR MIT | pest-parser/pest | +| pico-args | MIT | RazrFalcon/pico-args | +| pin-project | Apache-2.0 OR MIT | taiki-e/pin-project | +| pin-project-internal | Apache-2.0 OR MIT | taiki-e/pin-project | +| pin-project-lite | Apache-2.0 OR MIT | taiki-e/pin-project-lite | +| pin-project-lite | Apache-2.0 OR MIT | taiki-e/pin-project-lite | +| pin-utils | Apache-2.0 OR MIT | rust-lang-nursery/pin-utils | +| pkg-config | Apache-2.0 OR MIT | rust-lang/pkg-config-rs | +| png | Apache-2.0 OR MIT | image-rs/image-png.git | +| polling | Apache-2.0 OR MIT | smol-rs/polling | +| ppv-lite86 | Apache-2.0 OR MIT | cryptocorrosion/cryptocorrosion | +| proc-macro-error | Apache-2.0 OR MIT | | +| proc-macro-error-attr | Apache-2.0 OR MIT | | +| proc-macro-hack | Apache-2.0 OR MIT | dtolnay/proc-macro-hack | +| proc-macro-nested | Apache-2.0 OR MIT | dtolnay/proc-macro-hack | +| proc-macro2 | Apache-2.0 OR MIT | dtolnay/proc-macro2 | +| prometheus | Apache-2.0 | tikv/rust-prometheus | +| protobuf | MIT | stepancheg/rust-protobuf/ | +| quote | Apache-2.0 OR MIT | dtolnay/quote | +| rand | Apache-2.0 OR MIT | rust-random/rand | +| rand | Apache-2.0 OR MIT | rust-random/rand | +| rand\_chacha | Apache-2.0 OR MIT | rust-random/rand | +| rand\_chacha | Apache-2.0 OR MIT | rust-random/rand | +| rand\_core | Apache-2.0 OR MIT | rust-random/rand | +| rand\_core | Apache-2.0 OR MIT | rust-random/rand | +| rand\_hc | Apache-2.0 OR MIT | rust-random/rand | +| rand\_hc | Apache-2.0 OR MIT | rust-random/rand | +| rayon | Apache-2.0 OR MIT | rayon-rs/rayon | +| rayon-core | Apache-2.0 OR MIT | rayon-rs/rayon | +| rctree | MIT | RazrFalcon/rctree | +| redox\_syscall | MIT | | +| redox\_syscall | MIT | | +| redox\_users | MIT | | +| regex | Apache-2.0 OR MIT | rust-lang/regex | +| regex-automata | MIT OR Unlicense | BurntSushi/regex-automata | +| regex-syntax | Apache-2.0 OR MIT | rust-lang/regex | +| remove\_dir\_all | Apache-2.0 OR MIT | XAMPPRocky/remove\_dir\_all.git | +| reqwest | Apache-2.0 OR MIT | seanmonstar/reqwest | +| resvg | MPL-2.0 | RazrFalcon/resvg | +| rgb | MIT | kornelski/rust-rgb | +| roxmltree | Apache-2.0 OR MIT | RazrFalcon/roxmltree | +| rstar | Apache-2.0 OR MIT | georust/rstar | +| run\_script | Apache-2.0 | sagiegurari/run\_script.git | +| rust-embed | MIT | pyros2097/rust-embed | +| rust-embed-impl | MIT | pyros2097/rust-embed | +| rust-embed-utils | MIT | pyros2097/rust-embed | +| rustc-demangle | Apache-2.0 OR MIT | alexcrichton/rustc-demangle | +| rustc-hash | Apache-2.0 OR MIT | rust-lang-nursery/rustc-hash | +| rustc\_version | Apache-2.0 OR MIT | Kimundi/rustc-version-rs | +| rustc\_version | Apache-2.0 OR MIT | Kimundi/rustc-version-rs | +| rustc\_version | Apache-2.0 OR MIT | Kimundi/rustc-version-rs | +| rustversion | Apache-2.0 OR MIT | dtolnay/rustversion | +| rustybuzz | MIT | RazrFalcon/rustybuzz | +| ryu | Apache-2.0 OR BSL-1.0 | dtolnay/ryu | +| safe\_arch | Apache-2.0 OR MIT OR Zlib | Lokathor/safe\_arch | +| same-file | MIT OR Unlicense | BurntSushi/same-file | +| schannel | MIT | steffengy/schannel-rs | +| scoped\_threadpool | MIT | Kimundi/scoped-threadpool-rs | +| scopeguard | Apache-2.0 OR MIT | bluss/scopeguard | +| security-framework | Apache-2.0 OR MIT | kornelski/rust-security-framework | +| security-framework-sys | Apache-2.0 OR MIT | kornelski/rust-security-framework | +| semver | Apache-2.0 OR MIT | dtolnay/semver | +| semver | Apache-2.0 OR MIT | steveklabnik/semver | +| semver | Apache-2.0 OR MIT | steveklabnik/semver | +| semver-parser | Apache-2.0 OR MIT | steveklabnik/semver-parser | +| semver-parser | Apache-2.0 OR MIT | steveklabnik/semver-parser | +| sentry | Apache-2.0 | getsentry/sentry-rust | +| sentry-backtrace | Apache-2.0 | getsentry/sentry-rust | +| sentry-contexts | Apache-2.0 | getsentry/sentry-rust | +| sentry-core | Apache-2.0 | getsentry/sentry-rust | +| sentry-log | Apache-2.0 | getsentry/sentry-rust | +| sentry-panic | Apache-2.0 | getsentry/sentry-rust | +| sentry-types | Apache-2.0 | getsentry/sentry-rust | +| serde | Apache-2.0 OR MIT | serde-rs/serde | +| serde\_derive | Apache-2.0 OR MIT | serde-rs/serde | +| serde\_json | Apache-2.0 OR MIT | serde-rs/json | +| serde\_urlencoded | Apache-2.0 OR MIT | nox/serde\_urlencoded | +| serde\_with | Apache-2.0 OR MIT | jonasbb/serde\_with | +| serde\_with\_macros | Apache-2.0 OR MIT | jonasbb/serde\_with/ | +| serde\_yaml | Apache-2.0 OR MIT | dtolnay/serde-yaml | +| servo-fontconfig | Apache-2.0 OR MIT | servo/rust-fontconfig/ | +| servo-fontconfig-sys | MIT | servo/libfontconfig/ | +| shellexpand | Apache-2.0 OR MIT | netvl/shellexpand | +| shellwords | MIT | jimmycuadra/rust-shellwords | +| shlex | Apache-2.0 OR MIT | comex/rust-shlex | +| signal-hook | Apache-2.0 OR MIT | vorner/signal-hook | +| signal-hook | Apache-2.0 OR MIT | vorner/signal-hook | +| signal-hook-registry | Apache-2.0 OR MIT | vorner/signal-hook | +| simplecss | Apache-2.0 OR MIT | RazrFalcon/simplecss | +| simplelog | Apache-2.0 OR MIT | drakulix/simplelog.rs | +| simplelog | Apache-2.0 OR MIT | drakulix/simplelog.rs | +| siphasher | Apache-2.0 OR MIT | jedisct1/rust-siphash | +| slab | MIT | tokio-rs/slab | +| smallvec | Apache-2.0 OR MIT | servo/rust-smallvec | +| smallvec | Apache-2.0 OR MIT | servo/rust-smallvec | +| smart-default | MIT | idanarye/rust-smart-default | +| smol | Apache-2.0 OR MIT | stjepang/smol | +| socket2 | Apache-2.0 OR MIT | alexcrichton/socket2-rs | +| socket2 | Apache-2.0 OR MIT | rust-lang/socket2 | +| stable\_deref\_trait | Apache-2.0 OR MIT | storyyeller/stable\_deref\_trait | +| strsim | MIT | dguo/strsim-rs | +| strsim | MIT | dguo/strsim-rs | +| svgfilters | MPL-2.0 | RazrFalcon/resvg/tree/master/svgfilters | +| svgtypes | Apache-2.0 OR MIT | RazrFalcon/svgtypes | +| syn | Apache-2.0 OR MIT | dtolnay/syn | +| synstructure | MIT | mystor/synstructure | +| sysinfo | MIT | GuillaumeGomez/sysinfo | +| tempfile | Apache-2.0 OR MIT | Stebalien/tempfile | +| termcolor | MIT OR Unlicense | BurntSushi/termcolor | +| textwrap | MIT | mgeisler/textwrap | +| thiserror | Apache-2.0 OR MIT | dtolnay/thiserror | +| thiserror-impl | Apache-2.0 OR MIT | dtolnay/thiserror | +| thread\_local | Apache-2.0 OR MIT | Amanieu/thread\_local-rs | +| tiff | MIT | image-rs/image-tiff | +| time | Apache-2.0 OR MIT | time-rs/time | +| tiny-skia | BSD-3-Clause | RazrFalcon/tiny-skia | +| tinyvec | Apache-2.0 OR MIT OR Zlib | Lokathor/tinyvec | +| tinyvec\_macros | Apache-2.0 OR MIT OR Zlib | Soveu/tinyvec\_macros | +| tokio | MIT | tokio-rs/tokio | +| tokio | MIT | tokio-rs/tokio | +| tokio-native-tls | MIT | tokio-rs/tls | +| tokio-util | MIT | tokio-rs/tokio | +| tokio-util | MIT | tokio-rs/tokio | +| tower-service | MIT | tower-rs/tower | +| tracing | MIT | tokio-rs/tracing | +| tracing-core | MIT | tokio-rs/tracing | +| tracing-futures | MIT | tokio-rs/tracing | +| tree-sitter | MIT | tree-sitter/tree-sitter | +| try-lock | MIT | seanmonstar/try-lock | +| ttf-parser | Apache-2.0 OR MIT | RazrFalcon/ttf-parser | +| ttf-parser | Apache-2.0 OR MIT | RazrFalcon/ttf-parser | +| typenum | Apache-2.0 OR MIT | paholg/typenum | +| ucd-trie | Apache-2.0 OR MIT | BurntSushi/ucd-generate | +| uname | Apache-2.0 OR MIT | icorderi/rust-uname | +| uneval | MIT | Cerber-Ursi/uneval | +| unicode-bidi | Apache-2.0 OR MIT | servo/unicode-bidi | +| unicode-bidi-mirroring | Apache-2.0 OR MIT | RazrFalcon/unicode-bidi-mirroring | +| unicode-ccc | Apache-2.0 OR MIT | RazrFalcon/unicode-ccc | +| unicode-general-category | Apache-2.0 | yeslogic/unicode-general-category | +| unicode-normalization | Apache-2.0 OR MIT | unicode-rs/unicode-normalization | +| unicode-script | Apache-2.0 OR MIT | unicode-rs/unicode-script | +| unicode-segmentation | Apache-2.0 OR MIT | unicode-rs/unicode-segmentation | +| unicode-vo | Apache-2.0 OR MIT | RazrFalcon/unicode-vo | +| unicode-width | Apache-2.0 OR MIT | unicode-rs/unicode-width | +| unicode-xid | Apache-2.0 OR MIT | unicode-rs/unicode-xid | +| unicode\_categories | Apache-2.0 OR MIT | swgillespie/unicode-categories | +| unindent | Apache-2.0 OR MIT | dtolnay/indoc | +| unreachable | Apache-2.0 OR MIT | reem/rust-unreachable.git | +| url | Apache-2.0 OR MIT | servo/rust-url | +| urlocator | Apache-2.0 OR MIT | alacritty/urlocator.git | +| users | MIT | ogham/rust-users | +| usvg | MPL-2.0 | RazrFalcon/resvg | +| utf8parse | Apache-2.0 OR MIT | jwilm/vte | +| uuid | Apache-2.0 OR MIT | uuid-rs/uuid | +| validator | MIT | Keats/validator | +| validator\_types | MIT | Keats/validator | +| vcpkg | Apache-2.0 OR MIT | mcgoo/vcpkg-rs | +| vec1 | Apache-2.0 OR MIT | rustonaut/vec1/ | +| vec\_map | Apache-2.0 OR MIT | contain-rs/vec-map | +| version-compare | MIT | timvisee/version-compare | +| version\_check | Apache-2.0 OR MIT | SergioBenitez/version\_check | +| void | MIT | reem/rust-void.git | +| vte | Apache-2.0 OR MIT | alacritty/vte | +| vte\_generate\_state\_changes | Apache-2.0 OR MIT | jwilm/vte | +| wait-timeout | Apache-2.0 OR MIT | alexcrichton/wait-timeout | +| waker-fn | Apache-2.0 OR MIT | stjepang/waker-fn | +| walkdir | MIT OR Unlicense | BurntSushi/walkdir | +| want | MIT | seanmonstar/want | +| wasi | Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT | bytecodealliance/wasi | +| wasi | Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT | bytecodealliance/wasi | +| wasm-bindgen | Apache-2.0 OR MIT | rustwasm/wasm-bindgen | +| wasm-bindgen-backend | Apache-2.0 OR MIT | rustwasm/wasm-bindgen/tree/master/crates/backend | +| wasm-bindgen-futures | Apache-2.0 OR MIT | rustwasm/wasm-bindgen/tree/master/crates/futures | +| wasm-bindgen-macro | Apache-2.0 OR MIT | rustwasm/wasm-bindgen/tree/master/crates/macro | +| wasm-bindgen-macro-support | Apache-2.0 OR MIT | rustwasm/wasm-bindgen/tree/master/crates/macro-support | +| wasm-bindgen-shared | Apache-2.0 OR MIT | rustwasm/wasm-bindgen/tree/master/crates/shared | +| web-sys | Apache-2.0 OR MIT | rustwasm/wasm-bindgen/tree/master/crates/web-sys | +| webbrowser | Apache-2.0 OR MIT | amodm/webbrowser-rs | +| weezl | Apache-2.0 OR MIT | image-rs/lzw.git | +| wepoll-ffi | Apache-2.0 OR BSD-2-Clause OR MIT | aclysma/wepoll-ffi | +| which | MIT | harryfei/which-rs.git | +| widestring | Apache-2.0 OR MIT | starkat99/widestring-rs.git | +| winapi | Apache-2.0 OR MIT | retep998/winapi-rs | +| winapi | MIT | retep998/winapi-rs | +| winapi-build | MIT | retep998/winapi-rs | +| winapi-i686-pc-windows-gnu | Apache-2.0 OR MIT | retep998/winapi-rs | +| winapi-util | MIT OR Unlicense | BurntSushi/winapi-util | +| winapi-x86\_64-pc-windows-gnu | Apache-2.0 OR MIT | retep998/winapi-rs | +| winreg | MIT | gentoo90/winreg-rs | +| wio | Apache-2.0 OR MIT | retep998/wio-rs | +| ws2\_32-sys | MIT | retep998/winapi-rs | +| xmlparser | Apache-2.0 OR MIT | RazrFalcon/xmlparser | +| xmlwriter | MIT | RazrFalcon/xmlwriter | +| yaml-rust | Apache-2.0 OR MIT | chyh1990/yaml-rust | + +## ScanCode licenses + +| Name | License | Copyright | +| ----------- | ---------- | ---------------------------------------------: | +| Alacritty | APACHE-2.0 | Copyright 2016 Joe Wilm, The Alacritty Project | +| Hack Font | MIT | (c) 2018 Source Foundry Authors | +| Roboto Font | APACHE-2.0 | Copyright 2011 Google Inc. | +| Rubik Font | OFL-1.1 | Copyright 2015 The Rubik Project | +| Tree Sitter | MIT | Copyright (c) 2018 NAN contributors | diff --git a/src/content/docs/support-and-community/community/open-source-partnership.mdx b/src/content/docs/support-and-community/community/open-source-partnership.mdx new file mode 100644 index 0000000..077761a --- /dev/null +++ b/src/content/docs/support-and-community/community/open-source-partnership.mdx @@ -0,0 +1,30 @@ +--- +title: Oz Open Source Partnership +description: >- + Warp supports high-impact open source projects with free Oz agent credits + through the Oz Open Source Partnership program. +--- + +Warp is committed to supporting the open source community. Through the Oz Open Source Partnership program, we offer free Oz agent usage credits to high-impact open source projects, helping maintainers and contributors accelerate their development workflows. + +## What you get + +* **Free Oz credits** - Receive complimentary credits to run Oz agents on your open source project +* **Oz agent access** - Use cloud agents to automate tasks like code review, bug triage, documentation, and more across your repositories +* **Ongoing support** - Warp partners with accepted projects to ensure they get the most value from Oz agents + +## Who can apply + +The Oz Open Source Partnership program is designed for actively maintained, high-impact open source projects. When reviewing applications, we consider factors like community size, project activity, and the potential impact of Oz agents on your workflow. + +:::note +Have questions about the program? Reach out to us at [support@warp.dev](mailto:support@warp.dev). +::: + +## How to apply + +Tell us about your open source project by filling out the [application form](https://tally.so/r/LZWxqG). We'll review your submission and follow up with next steps. + +:::note +The Oz Open Source Partnership program provides free Oz agent credits for open source projects. This is separate from Warp's open source client — the Warp client is published under AGPL v3 at [`warpdotdev/warp`](https://github.com/warpdotdev/warp); see [Contributing to Warp](/support-and-community/community/contributing/). For sponsorship opportunities for your project, reach out to [partnerships@warp.dev](mailto:partnerships@warp.dev). +::: diff --git a/src/content/docs/support-and-community/community/refer-a-friend.mdx b/src/content/docs/support-and-community/community/refer-a-friend.mdx new file mode 100644 index 0000000..1af5046 --- /dev/null +++ b/src/content/docs/support-and-community/community/refer-a-friend.mdx @@ -0,0 +1,127 @@ +--- +title: Refer a friend and earn rewards +description: >- + Think Warp would be the ideal product for someone you know? You can invite + your team or friends within the app and earn rewards. +--- + +:::note +Go to **Settings** > **Referrals** to open the invite a friend referral dialog. +::: + +**There are two ways you can invite a friend:** + +1. Send them an invite link. They will be directed to our product download page. +2. Input their email address, which we'll use to email them with your referral link. + +## Referral rewards program + +We give out themes, swag, and other perks as thanks for helping to grow our community. + +The tiers are as follows: + +| Referrals | Reward | Digital Gift Card Alternative | +| --------- | -------------------- | :---------------------------: | +| 1 | Exclusive Theme | $0 | +| 5 | Stickers and Keycaps | $5 | +| 10 | T-Shirt | $10 | +| 20 | Moleskin Notebook | $20 | +| 35 | Baseball Hat | $35 | +| 50 | Hoodie | $50 | +| 75 | Hydroflask | $75 | +| 100 | North Face Backpack | $100 | + +By participating in Warp's referral program, you agree to the [Referral program terms and conditions](/support-and-community/community/refer-a-friend/#referral-program-terms-and-conditions). + +### Your friend gets a theme + +If your friend joins and activates their Warp account after clicking your invite link, they will receive a unique theme. + +## Referral program terms and conditions + +> **Last Updated:** November 27, 2024 + +### 1 referral: An exclusive theme + +When someone joins Warp with your referral code, the referral theme will become available in your theme picker after you restart the app. We also send an email alerting you. This reward is available to all users worldwide. + +### All other referral tiers + +Once you've hit the other referral tiers, we'll email you with details on how to claim your reward. Physical rewards are available to users residing in the United States, and Warp will cover shipping costs for these users. International users can also claim physical rewards; however, they will be responsible for any customs fees. For all users, there's an option to claim a digital reward (gift card) instead of physical Warp swag. + +### International users + +International users who choose physical rewards are responsible for paying any customs fees associated with shipping. Estimated costs are provided in the [approximate customs fees by region](/support-and-community/community/refer-a-friend/#approximate-customs-fees-by-region) section below. Please note that once the package leaves the United States, Warp no longer has visibility or control over the shipment process, including any customs-related issues or fees that may arise. + +Alternatively, international users may opt to receive a digital gift card instead of a physical reward. + +Note: for users who qualified for referral rewards before October 15th, 2024, Warp will cover all shipping and customs costs. Starting from that date onwards, international users receiving referral rewards will be responsible for paying any customs fees associated with shipping. + +### Shipping time frame + +Physical rewards may take 2 to 3 weeks to arrive for users located in the United States, and 4 to 12 weeks for international users. After claiming your order, you will receive an email with a shipping confirmation and a tracking link from Printfection, our swag vendor. + +If you have any questions about the status of your shipment or order, please reach out to support@printfection.com with your order number. + +### General terms and conditions + +Referrals must be valid and confirmed by Warp to count towards rewards. This means the referred user must accept the referral via the referral link and log into Warp's desktop application. + +Warp reserves the right, at its sole discretion, to disqualify any referrals deemed fraudulent. Any users who refer fake emails or users will be disqualified at the sole discretion of Warp. + +Warp reserves the right to modify or terminate the referral rewards program at any time without prior notice. Participation in the swag program constitutes acceptance of these terms and conditions. + +If you have any questions about the referral program, please contact [referrals@warp.dev](mailto:referrals@warp.dev). + +### Digital gift card rewards + +All amounts are listed in USD. Rewards are based on the number of valid referrals. + +| Number of referrals | Gift card amount | +| :-----------------: | :--------------: | +| 1 | $0 | +| 5 | $5 | +| 10 | $10 | +| 20 | $20 | +| 35 | $35 | +| 50 | $50 | +| 75 | $75 | +| 100 | $100 | + +### Approximate customs fees by region + +All amounts are listed in USD. Fees are estimates and may vary regardless of package size. + +| Country / region | Approximate customs fees | +| :-------------------------------------------------: | :----------------------: | +| Canada & Mexico | $40 to $70 | +| Europe | $40 to $80 | +| Others (Asia, South America, Africa, Oceania, etc.) | $50 to $120 | + +\*Note: The approximate customs fees provided are estimates and may vary based on your country's specific import regulations, taxes, and duties. Actual fees can differ due to factors such as package contents, declared value, and current customs policies. We recommend checking with your local customs office or postal service for precise information relevant to your situation. + +## Referral rewards program FAQs + +#### **"I have referred people but have not received an email."** + +Please allow a few hours for the referral system to process and send email updates. If you still haven’t received an email after a reasonable amount of time, contact us at [referrals@warp.dev](mailto:referrals@warp.dev) and we'll look into it. + +#### **"I've claimed my physical reward but have issues receiving my package."** + +If you experience issues with your shipment, please respond to the shipping notification email you should have received from Printfection. For further assistance, contact our swag vendor’s operations team at [support@printfection.com](mailto:support@printfection.com) with your order number. + +#### **"I've referred friends, but they didn't use the link. Does it still count?"** + +Unfortunately, any referrals who didn't use your link will not count towards the rewards, and we have no way of modifying the referral count. + +#### **"I've referred friends, but they joined anonymously. Does it still count?"** + +For a referral to count, new users must sign up and actively use Warp. Unfortunately, we’re unable to associate anonymous users with specific referral links at this time. + +We’re actively working on solutions to make the referral process more seamless and reliable for anonymous users. Stay tuned for updates as we improve this experience. + +#### **"The reward tiers recently changed with the new swag items. I previously qualified for X. What happens now, and are the new swag items retroactive?"** + +Our referral program was updated on November 21, 2024, with new reward tiers and exciting swag options. To ensure a smooth transition, we will honor previous reward tiers alongside the updated program until December 15, 2024. + +If you’re unsure how these changes impact your previous qualifications or eligibility for the new swag items, feel free to reach out to us at referrals@warp.dev for assistance. diff --git a/src/content/docs/support-and-community/community/warp-preview-and-alpha-program.mdx b/src/content/docs/support-and-community/community/warp-preview-and-alpha-program.mdx new file mode 100644 index 0000000..9ea0954 --- /dev/null +++ b/src/content/docs/support-and-community/community/warp-preview-and-alpha-program.mdx @@ -0,0 +1,34 @@ +--- +title: Warp Preview +description: >- + Warp Preview is an early-access build of Warp with experimental features. + Try what's next before it ships. +--- + +Warp Preview is an early-access program that allows you to explore Warp's newest and most experimental features. It’s independent from the stable build, so you can always revert to a reliable version of Warp whenever you need it. + +### Key Warp Preview features + +* **Early access** - Try out experimental features before they're officially released. +* **Faster updates** - Enjoy frequent updates and patches as we refine new capabilities. +* **Direct impact** - Your feedback plays a critical role in shaping Warp's future. + +To learn more about Warp Preview, check out our [launch blog post](https://warp.dev/blog/warp-preview). + +### Getting started with Warp Preview + +1. **Download**: Get the Warp Preview build from [warp.dev/download-preview](https://warp.dev/download-preview). +2. **Sign in**: [Log in](/getting-started/quickstart/installation-and-setup/#log-in-to-warp-optional) with your Warp account (not optional for Warp Preview). +3. **Run side-by-side**: You can keep Warp Preview alongside your stable Warp installation. + +### Important notes + +* **Experimental build** - Expect occasional bugs or incomplete features. +* **Login required** - You must sign in to use Warp Preview. This helps us gather feedback, quickly diagnose critical issues, and ensure we can reach out if you need support. +* **Flexibility** - Switch between Preview and Stable builds at any time. +* **Distinct icon** - Warp Preview uses a unique icon to help distinguish it from the stable version. + +### Providing Warp Preview feedback + +Share feedback, report bugs, and discuss Preview features in the [community Slack](https://go.warp.dev/join-preview). You can also [send feedback directly from the app](/support-and-community/troubleshooting-and-support/sending-us-feedback/#sending-warp-feedback). + diff --git a/src/content/docs/support-and-community/index.mdx b/src/content/docs/support-and-community/index.mdx new file mode 100644 index 0000000..3621713 --- /dev/null +++ b/src/content/docs/support-and-community/index.mdx @@ -0,0 +1,59 @@ +--- +title: Support & Community +description: >- + Connect with the developers and engineers building with Warp. Share what + you've built, shape what we build next, and get help when you're stuck. +--- +## Find your space + +### Join the community + +Our Slack community is where workflows get shared, bugs get squashed, and ideas turn into features. Talk directly with Warp engineers and other developers. + +:::tip +[**Join the Warp community on Slack**](https://go.warp.dev/join-preview) +::: + +Built something with Warp? An agent workflow, a CLI tool, a creative terminal setup? Drop it in `#how-do-you-warp` — we spotlight community projects regularly. + +### Build with us on GitHub + +Bugs, feature requests, and what's shipping next. Your upvotes decide what we prioritize. + +[**Open an issue**](https://github.com/warpdotdev/warp/issues) + +Warp's client is open source. See [Contributing to Warp](/support-and-community/community/contributing/) for the full set of contribution paths, including opening pull requests, contributing themes and workflows, and sharing Warp Drive objects. + +### Attend events + +We host [live events](https://luma.com/warpdotdev) year-round — product demos, launch celebrations, community Q&As, and more. One recurring favorite: + +:::note +**Warp 101 livestreams** — A live walkthrough of Warp features, tips, and Q&A with the team, held every two weeks. [**Register for upcoming events on Luma**](https://luma.com/warpdotdev) +::: + +### Follow along + +* [**X**](https://x.com/warpdotdev) - What we're shipping and what the community is building +* [**YouTube**](https://www.youtube.com/@warpdotdev) - Tutorials, demos, and product deep dives +* [**LinkedIn**](https://www.linkedin.com/company/warpdotdev) - Engineering deep dives and company news +* [**Reddit**](https://www.reddit.com/r/warpdotdev/) - Unfiltered discussions, feature debates, and Q&A + +## Programs + +* [**Warp Preview**](/support-and-community/community/warp-preview-and-alpha-program/) — Try experimental features before anyone else. Your feedback directly shapes what ships. +* [**Refer a Friend**](/support-and-community/community/refer-a-friend/) — Send Warp to a developer you think would love it. Earn themes, swag, and gift cards. +* [**Oz Open Source Partnership**](/support-and-community/community/open-source-partnership/) — Free Oz agent credits for high-impact open source projects. + +:::note +**Ambassador program** + +We're building an Ambassador program for developers who want to lead and grow the Warp community. Join the [community Slack](https://go.warp.dev/join-preview) to hear when applications open. +::: + +## Get help + +* [Sending us feedback](/support-and-community/troubleshooting-and-support/sending-us-feedback/) +* [Known issues](/support-and-community/troubleshooting-and-support/known-issues/) +* [Plans, pricing, and refunds](/support-and-community/plans-and-billing/plans-pricing-refunds/) +* [Privacy](/support-and-community/privacy-and-security/privacy/) diff --git a/src/content/docs/support-and-community/plans-and-billing/add-on-credits.mdx b/src/content/docs/support-and-community/plans-and-billing/add-on-credits.mdx new file mode 100644 index 0000000..8b032f0 --- /dev/null +++ b/src/content/docs/support-and-community/plans-and-billing/add-on-credits.mdx @@ -0,0 +1,106 @@ +--- +title: Add-on Credits +description: >- + Purchase Add-on Credits to keep using premium AI models after reaching your + monthly credit limit. +--- + +Add-on credits replace Warp's old [pay-as-you-go Overages](/support-and-community/plans-and-billing/overages-legacy/). They let you continue using premium AI models even after you've reached your monthly credit limit — at lower rates and with more control over spending. + +You can manage and purchase Add-on credits directly in **Settings** > **Billing and usage**. + +![Add-on Credits management surface under Settings > Billing and usage.](../../../../assets/support-and-community/reload-credits.png) + +### How do Add-on credits work? + +Add-on credits extend your AI usage beyond the included monthly quota in your plan. Once your plan’s credits are used up, Warp will automatically begin drawing from your available Add-on credits. + +If you’ve enabled **Auto reload**, new credits will be added automatically and billed based on your selected configuration of monthly spending limit and selected purchase amount. + +Add-on credits are available for Build, Business, and Enterprise plans (with custom pricing for Enterprise). These credits **roll over across billing cycles** and remain valid for **12 months from the purchase date**. + +:::caution +**Legacy plans (Pro, Turbo, Lightspeed) do not support Add-on Credits.** If you're on a legacy plan, you cannot purchase or auto-reload Add-on Credits. To access Add-on Credits, upgrade to the [Build plan](https://app.warp.dev/upgrade). For additional usage on legacy plans, see [Overages (Legacy)](/support-and-community/plans-and-billing/overages-legacy/). +::: + +### Purchasing Add-on credits + +You have two options for purchasing more credits: + +#### 1. Buy on-demand + +You can purchase additional Add-on credits at any time directly within the app under **Settings** > **Billing and usage**. Buying more credits upfront provides a larger discount. + +The table below shows the available credit denominations, their prices, and corresponding discounts: + +<table><thead><tr><th width="115.21023559570312">Credits</th><th width="194.0745849609375">Price (USD)</th><th>Price per Credit</th><th>Discount</th></tr></thead><tbody><tr><td>400</td><td>$10</td><td>$0.025</td><td>Base rate</td></tr><tr><td>1,000</td><td>$20</td><td>$0.020</td><td>20% off</td></tr><tr><td>3,000</td><td>$50</td><td>$0.016</td><td>~35% off</td></tr><tr><td>6,500</td><td>$100</td><td>$0.0153</td><td>~40% off</td></tr></tbody></table> + +#### 2. Enable auto-reload + +Auto reload automatically purchases more credits whenever your balance reaches **100 credits**, ensuring uninterrupted access to premium AI features. + +By default, **Auto reload is disabled for new subscribers**. When you turn it on, it starts with a **$200 monthly spend limit**, which you can adjust anytime in **Settings** > **Billing and usage**. + +Auto reload uses the same denominations and discounts as manual purchases. The denomination you select (e.g., 400, 1,000, 3,000, or 6,500 credits) will repeat each time your balance is depleted, up to your monthly spending limit. Larger denominations offer up to \~40% off per credit. + +:::note +You can opt in and choose your reload amount when subscribing to a paid plan at [app.warp.dev/upgrade](https://app.warp.dev/upgrade), or change your configuration anytime in **Settings** > **Billing and usage**. +::: + +:::caution +Add-on credit auto reload will be enabled by default for some legacy plan users when they transition to the Build plan. Please see more in our [Pricing FAQs](/support-and-community/plans-and-billing/pricing-faqs/#what-happens-to-my-current-plan-pro-turbo-lightspeed). +::: + +#### **Configuring a monthly spend limit** + +Your monthly spend limit sets the maximum amount you can spend on Add-on credits in a single calendar month. This ensures you have full control over your AI usage costs while still allowing flexibility for automatic top-ups when needed, keeping your workflow uninterrupted. + +* The default limit is $200, but you can increase or decrease it anytime in **Settings** > **Billing and usage**. +* **If a credit purchase would exceed your limit, it won’t process** — you’ll need to either raise your limit or choose a smaller Add-on credit amount. +* Once your limit is reached, no additional Add-on Credit purchases (manual or automatic) will occur until: + * The next calendar month begins, or + * You update your limit in settings. + +:::caution +Your monthly spend limit is separate from your billing cycle (which determines when your subscription renews).\ +\ +The limit resets automatically at the start of each calendar month, so you can manage recurring AI usage with predictable spending and clear visibility into your costs. +::: + +### Billing and credit usage + +When your monthly credit balance renews: + +1. Warp first consumes your included monthly plan credits (e.g., Build plan credits). +2. After those are used, Warp continues to draw from any available Add-on Credits. +3. If your Add-on Credits run out and Auto reload is enabled, Warp will automatically purchase more up to your monthly limit. + +You can track your remaining credits and spending in the credits transparency footer and in **Settings** > **Billing and usage**. + +#### Teams using Add-on Credits + +For teams on Build or Business plans, **Add-on Credits are shared across all members.** All team credit settings can be managed in `Settings → Billing and usage` by the admin of the team. + +Team admins can manage: + +* Enabling or disabling Auto reload +* Adjusting monthly spend limits +* Choosing Add-on credit increments +* Viewing usage and spending breakdowns + +Each user on the team has their own monthly credit limit, **but any usage beyond that personal quota draws from the shared team credits**. These shared credits are tracked and billed collectively at the team level. + +For example, if your plan includes 1,500 credits per team member: + +* If **User A** reaches their 1,500 limit, any further usage will draw from shared Add-on Credits. +* If **User B** has only used 200 credits, their remaining quota is unaffected, but User A will consume the team's shared credits. + +### Plan changes and cancellations + +Any purchased Add-on Credits remain in your account and can continue to be used for up to 12 months after purchase, as long as you have an active subscription. + +If you move to the Free plan, you'll lose access to any previously purchased Add-on Credits and won't be able to use them. You also can't buy additional Add-on Credits until you're subscribed again. + +:::note +All unused Add-on Credits remain valid for 12 months from purchase, as long as you have an active subscription. +::: diff --git a/src/content/docs/support-and-community/plans-and-billing/bring-your-own-api-key.mdx b/src/content/docs/support-and-community/plans-and-billing/bring-your-own-api-key.mdx new file mode 100644 index 0000000..cd2f84c --- /dev/null +++ b/src/content/docs/support-and-community/plans-and-billing/bring-your-own-api-key.mdx @@ -0,0 +1,122 @@ +--- +title: Bring Your Own API Key +description: >- + Warp's paid plans include the ability to bring your own API keys (BYOK) for + OpenAI, Anthropic, and Google AI models. +--- + +Warp supports **Bring Your Own Key (BYOK)** for users who want to connect Warp’s agent to their own Anthropic, OpenAI, or Google API accounts. + +This lets you use your own API keys to access models directly, giving you full control over model selection, billing, and data routing. See [Model Choice](/agent-platform/capabilities/model-choice/) for a list of supported models. + +BYOK provides greater flexibility in model access and ensures Warp **never consumes your** [credits](/support-and-community/plans-and-billing/credits/) for requests routed through your own keys. + +:::note +BYOK is currently only available on Warp's paid plans, starting with Build. Learn more about plans and pricing [warp.dev/pricing](https://www.warp.dev/pricing). +::: + +## How does BYOK work? + +When you add your own model API keys in Warp, those keys are stored **locally on your device** and are **never synced to the cloud**. + +Warp uses these API keys to directly route your agent requests to the model provider you've configured. + +:::caution +BYOK does not apply to [Oz Cloud Agents](/agent-platform/cloud-agents/overview/). Because your API keys are stored locally on your device, they are not available to cloud-hosted agent runs. Cloud agent runs always consume [Warp credits](/support-and-community/plans-and-billing/credits/). +::: + +When a model is selected using your own key: + +* Warp **does not consume** any of your [credits](/support-and-community/plans-and-billing/credits/). +* Costs are billed directly through your model provider account. +* Warp does not retain or store your API key on any of its servers. + +![Diagram showing how Warp routes BYOK agent requests directly through your provider API key, bypassing Warp credits.](../../../../assets/support-and-community/Pricing-Blog-BYOK.png) + +## Enabling BYOK + +To enable and configure your API keys: + +1. Open **Settings** and search for `API keys` to jump to the BYOK configuration. +2. Add your API key(s) for Anthropic, OpenAI, or Google. +3. Once added, you'll see a **key icon** next to supported models in the model picker. + +:::note +The BYOK configuration widget doesn't currently live on a dedicated sidebar subpage; searching from the **Settings** window is the quickest way to reach it. We're tracking a follow-up to surface it under a persistent sidebar entry. +::: + +![Key icon shown next to supported models in the model picker after BYOK API keys are configured.](../../../../assets/support-and-community/byok-keys.png) + +When you explicitly select a model with a key icon, Warp routes requests through your own API key instead of consuming Warp's credits. + +## BYOK usage and billing behavior + +### Auto Model + +Warp's **Auto** models dynamically route requests across different models based on context and performance. Because this routing logic depends on Warp’s infrastructure, **Auto always consumes Warp's credits**, even if you’ve configured your own API keys. + +To use your own key, select a specific provider model (for example, Claude Sonnet 4.5, GPT-5, or Gemini 2.5 Pro) directly from the model picker with a key icon. + +### Credit usage + +When you select a model with the key icon in your model picker, Warp routes the request through your API key. + +In this case: + +* No Warp credits are consumed. +* The cost of the request is billed directly through your provider account. +* Core Agent Mode always **prioritizes BYOK usage** over any available credits. + +The credit transparency footer will show “0 credits used”, and the `Billing & Usage` page will reflect no deductions from your monthly credit total. + +**Other AI features in Warp** + +Some AI-powered features are not affected by BYOK and are included as part of Warp’s paid plans. + +| Feature | Uses Warp's credits | Description | +| ----------------------------------------------------------------------------- | ------------------- | -------------------------------------------------------------------- | +| [Active AI Recommendations](/agent-platform/local-agents/active-ai/) | No | Always included with Build and higher plans. | +| [Codebase Context](/agent-platform/capabilities/codebase-context/) | Yes | Uses Warp's AI infrastructure and consumes credits. | +| [Oz Cloud Agents](/agent-platform/cloud-agents/overview/) | Yes | BYOK keys are stored locally and not available to cloud-hosted runs. | + +These features will continue to function normally regardless of whether you’ve configured BYOK. + +### Failover and fallback behavior + +If Warp detects an issue with your API key, you’ll see a clear error message corresponding with the AI request. + +If your key: + +* Is invalid: Warp notifies you and halts the request. +* Hits usage or rate limits: Warp will not retry using credits. +* You can update or replace your keys anytime by opening **Settings** and searching for `API keys`. + +**Failover and fallback:** + +By default, Warp does not fall back to your credits when a BYOK (Bring Your Own Key) request fails. + +You can choose to enable **Warp credit fallback**. When enabled, if an agent request fails with your BYOK model (for example, due to an API error or quota limit), Warp will automatically route the request to one of Warp’s provided models. Warp always prioritizes your API keys first and only uses Warp credits when necessary. + +![Setting to enable Warp credit fallback when a BYOK request fails.](../../../../assets/support-and-community/fallback.png) + +### Zero Data Retention (ZDR) and BYOK + +Warp is **SOC 2 compliant** and has **Zero Data Retention (ZDR)** policies with all of its contracted LLM providers. No customer AI data is retained, stored, or used for training by the model providers. + +However, when you use your own API key: + +* Data retention policies depend on your provider’s account settings. +* Warp cannot enforce ZDR for requests sent through your API keys. +* If your Anthropic, OpenAI, or Google account does not have ZDR enabled, your requests may be retained by the provider according to their terms. + +Warp itself never stores your LLM API keys. + +### BYOK on Enterprise and Business plans + +Currently, BYOK is configured at the **user level**, not the team or admin level: + +* Each team member can add and manage their own API keys locally. +* Team admins cannot yet enforce or share API keys across members. +* There is currently no organization-level Admin Panel for BYOK management. + +If your organization has specific needs for managed keys or enterprise-level control, please contact us at [warp.dev/contact-sales](https://warp.dev/contact-sales). diff --git a/src/content/docs/support-and-community/plans-and-billing/credits.mdx b/src/content/docs/support-and-community/plans-and-billing/credits.mdx new file mode 100644 index 0000000..e6b576a --- /dev/null +++ b/src/content/docs/support-and-community/plans-and-billing/credits.mdx @@ -0,0 +1,127 @@ +--- +title: Credits +description: >- + Details on Warp credits and how they are calculated. +--- + +### What are Warp credits? + +Any interaction with Warp's Agent consumes credits. Credits are primarily based on AI usage — the number of credits a task consumes varies based on the size and complexity of your codebase, the size of the task, the model you're using, the amount of context the agent needs to gather, and more. + +Credits also include a small hosting fee, charged only when running agents in the cloud, hosted on Warp's infrastructure. For details on cloud agent credits, see [Cloud Agent Credits](/support-and-community/plans-and-billing/credits/#cloud-agent-credits). + +Each interaction consumes **at least one credit**, though more complex interactions may use **multiple credits**. Because of factors such as codebase size, model choice, number of tool calls, and the nature of LLMs, credit usage is **non-deterministic** — two similar prompts can still use a different number of credits. + +:::note +For a general breakdown of what factors contribute to how many credits are consumed, please refer to: [How are Warp credits calculated?](/support-and-community/plans-and-billing/credits/#how-are-warp-credits-calculated) +::: + +Since there's no exact formula for predicting usage, we recommend building an intuitive understanding by experimenting with different prompts, models, and tracking how many credits they consume. + +**Tracking your credit usage** + +In an Agent conversation, a **turn** represents a single exchange (a response from the LLM). To see how many credits a turn consumed, hover over the **credit count chip** at the bottom of the Agent's response: + +![The conversation usage footer shows how many credits a conversation has consumed, and breaks down the usage by credits, tool calls, context window, files changed, diffs applied, and more.](../../../../assets/support-and-community/inline-credit-usage-footer.png) + +:::note +You can view your total credit usage, along with other billing details, in **Settings** > **Billing and usage**. +::: + +#### Credit **limits and billing** + +* **Seat-level allocation**: On team plans, credit limits apply per seat — each team member has their own allowance. Individual users (not on a team) also have their own credit allocation. +* **Cloud Agent Credits**: Individual users can run cloud agents via CLI/API using their normal Warp credits, [Cloud Agent Credits](/support-and-community/plans-and-billing/credits/#cloud-agent-credits), or a Build plan with available credits. Integrations (Slack, Linear) require team membership. +* **Hitting the credit limits**: Once you hit your monthly credit limit, your access will depend on your plan. On the Free plan, AI access stops until your next billing cycle. On paid plans, you can continue using AI with usage-based billing via [Add-on Credits](/support-and-community/plans-and-billing/add-on-credits/). + +#### **Other features that use credits** + +In addition to direct Agent conversations, the following features also consume credits: + +* [Generate](/agent-platform/local-agents/overview/) helps you look up commands and suggestions as you type. As you refine your input, multiple credits may be used before you select a final suggestion. +* [AI Autofill in Workflows](/knowledge-and-collaboration/warp-drive/workflows/#ai-autofill) counts as a credit each time it is run. + +:::tip +Regular shell commands in Warp do not consume or count towards credits. +::: + +### How are Warp credits calculated? + +A **credit** in Warp is a unit of work representing the total processing required to complete an interaction with an Agent. It is **not** the same as "one user message" — instead, it scales with the number of tokens processed during the interaction. + +In short: **the more tokens used, the more credits consumed**. + +Several factors influence how many credits are counted for a single interaction: + +#### **1. The LLM model used** + +Generally, smaller, faster models typically consume fewer credits than larger, reasoning-based models. + +For example, **Claude Opus 4.6** and **Claude Opus 4.5** tend to consume the most tokens and credits in Warp, followed by **Claude Sonnet 4.6, GPT-5.4, GPT-5.3 Codex, Gemini 3 Pro**, and others in roughly that order. This generally correlates with model pricing as well. + +:::note +**Tip**: If your task doesn't require deep reasoning, planning, or multi-step problem solving, choose a more lightweight model to reduce credit usage. +::: + +#### 2. Tool calls triggered by the Agent + +Warp's Agents make a variety of tool calls, including: + +* Searching for files (grep) +* Retrieving and reading files +* Making and applying code diffs +* Gathering web or documentation context +* Running other utilities + +Some prompts require only a couple of tool calls, while others may trigger many — especially if the Agent needs to explore your development environment, navigate a large codebase, or apply complex changes. **More tool calls = more credits**. + +#### 3. Task complexity and number of steps + +Some tasks are straightforward and may require only a single quick response, without much thinking or reasoning. Others can involve multiple stages—such as planning, generating intermediate outputs, verifying results, applying changes, and self-correcting—each of which can add to the credits count. + +:::note +**Tip**: Keep tasks that you give to the Agent well-scoped, work incrementally, and break large changes into smaller, contained steps. +::: + +#### 4. Amount of context passed to the model + +Prompts that include large amounts of context (such as [attached blocks](/agent-platform/local-agents/agent-context/blocks-as-context/), long user query messages, etc.) or file attachments like [images](/agent-platform/local-agents/agent-context/images-as-context/) may also increase the number of credits used due to increased token consumption. + +:::note +**Tip**: When sharing logs, code, or other large pieces of content, attach only the most relevant portions instead of full outputs. +::: + +#### 5. Prompt caching (hits and misses) + +Many model prompts include repeated content, like system instructions: + +* **Cache hits**: if the model provider can match a prefix or a part of the prompt from a past request, it can reuse results from the cache, reducing both tokens consumed and latency. +* **Cache misses**: if no match is found, the full prompt may be processed again, which can increase credit consumption. + +Because cache results depend on model provider behavior and timing, two similar prompts may still have different credit counts, depending on when you run the commands. + +:::note +**Tip**: Work in a continuous session when possible to improve cache hit rates. +::: + +These are the most common factors affecting credit usage, though there are others. Understanding them can help you manage your credits more efficiently and get the most from your plan. + +### Cloud Agent Credits + +Cloud Agent Credits are a type of credit consumed only by cloud agent runs — AI requests that run on Warp-hosted compute. + +#### Eligible for Cloud Agent Credits + +The following scenarios use Cloud Agent Credits: + +* **First-party integrations** — Running agents through Slack or Linear integrations +* **Cloud agent runs** — Using `oz agent run-cloud` via the CLI +* **Oz API** — Running agents through Warp's Oz API +* **Cloud Mode** — Running an agent from Cloud Mode in the Warp app + +#### Not eligible for Cloud Agent Credits + +The following scenarios do **not** use Cloud Agent Credits: + +* **Local agent runs** — Using `oz agent run` on your local machine +* **Self-hosted compute** — Using `oz agent run` on GitHub Actions, CI/CD pipelines, or other self-hosted infrastructure diff --git a/src/content/docs/support-and-community/plans-and-billing/index.mdx b/src/content/docs/support-and-community/plans-and-billing/index.mdx new file mode 100644 index 0000000..ae1490f --- /dev/null +++ b/src/content/docs/support-and-community/plans-and-billing/index.mdx @@ -0,0 +1,15 @@ +--- +title: Plans and billing +description: >- + Understand your Warp plan options, how credits work, and how to manage + billing settings. +--- + +Warp offers flexible plans designed for individual developers, teams, and enterprises. Learn about pricing, credits, and billing options. + +* [**Plans & Pricing**](/support-and-community/plans-and-billing/plans-pricing-refunds/) - Compare plans, pricing tiers, and refund policies +* [**Credits**](/support-and-community/plans-and-billing/credits/) - How credits are used and calculated across AI features +* [**Add-on Credits**](/support-and-community/plans-and-billing/add-on-credits/) - Purchase additional credits or enable automatic reloads +* [**Bring Your Own API Key**](/support-and-community/plans-and-billing/bring-your-own-api-key/) - Connect your own model provider API keys +* [**Overages (Legacy)**](/support-and-community/plans-and-billing/overages-legacy/) - Information for users on legacy plans with overages +* [**Pricing FAQs**](/support-and-community/plans-and-billing/pricing-faqs/) - Answers to common questions about plans and billing diff --git a/src/content/docs/support-and-community/plans-and-billing/overages-legacy.mdx b/src/content/docs/support-and-community/plans-and-billing/overages-legacy.mdx new file mode 100644 index 0000000..b3ebc2f --- /dev/null +++ b/src/content/docs/support-and-community/plans-and-billing/overages-legacy.mdx @@ -0,0 +1,40 @@ +--- +title: Overages (Legacy) +description: >- + Pay-as-you-go access to premium AI models after reaching your monthly + credits quota on Warps plans. +--- + +Warp offers usage-based pricing for Subscribers, allowing continued access to premium AI models even after reaching the monthly credits limit included in the plan (billed at $0.04 per additional credit). + +You can manage usage-based pricing directly in Warp under **Settings** > **Billing and usage**. + +![Billing and usage tab in settings, where admins can manage premium model usage overages](../../../../assets/support-and-community/overages-settings.png) + +### Enabling overages + +**Team admins** can enable or disable "premium model overages" and set a monthly spending limit from the settings dashboard. Individual subscribers can manage their own overage settings directly in the settings dashboard. + +:::note +Usage-based pricing only applies after you’ve reached the credit limit on your plan — you won’t be charged for any overages until that point, even if overages are enabled. +::: + +### How overages work + +Overages are managed **at the team level**, even if your team only has one member (i.e. individual users). Once overages are enabled, any team member who reaches their monthly credit quota can continue to have access to premium models — with **additional usage billed at cost ($0.04 per credit)**. + +Each user on the team has their **own credit limit**, but only **credits made beyond that personal quota** are considered overages. These charges are tracked and billed **collectively** at the team level. + +For example, if your plan includes 10,000 credits per team member: + +* If **User A** reaches their 10,000 limit, any further usage by them counts towards overages. +* If **User B** has only used 2,000 credits, they still have 8,000 included credits left. +* User A's overages **do not** consume User B's remaining quota. + +Overages are **billed monthly**, or when your team accumulates **$20 worth of charges**, whichever comes first. + +### Plan upgrades and cancellations + +If you upgrade from lower to a higher plan, your monthly credit limit will update immediately to match the higher plan. (For exact limits, see our [pricing page](https://www.warp.dev/pricing).) However, **any overages incurred while on the lower plan will still be billed** — upgrading does not retroactively remove or reduce existing overage charges. + +If you cancel your subscription, you’ll retain access to premium features until the end of your current billing period. Any usage-based overages accrued during that period will be charged at the time your plan ends.\\ diff --git a/src/content/docs/support-and-community/plans-and-billing/plans-pricing-refunds.mdx b/src/content/docs/support-and-community/plans-and-billing/plans-pricing-refunds.mdx new file mode 100644 index 0000000..74a24d5 --- /dev/null +++ b/src/content/docs/support-and-community/plans-and-billing/plans-pricing-refunds.mdx @@ -0,0 +1,54 @@ +--- +title: Plans, pricing, and refunds +description: >- + Learn about Warp's plans and pricing tiers. Get started for free. +--- + +## Warp plans and pricing + +Warp offers flexible, pay-as-you-go plans designed for individual developers, teams, and enterprises. + +You only pay for what you use—each plan includes a monthly allowance of credits that power features such as code generation, debugging, and multi-agent workflows. + +:::note +Visit [warp.dev/pricing](https://warp.dev/pricing) to see the latest plans and what’s included in each offering. +::: + +**Explore the following sections for more details:** + +* [Credits](/support-and-community/plans-and-billing/credits/) — learn how credits are used and calculated across AI features. +* [Add-on Credits](/support-and-community/plans-and-billing/add-on-credits/) — purchase additional credits or enable automatic reloads at discounted rates. +* [Bring Your Own API Key](/support-and-community/plans-and-billing/bring-your-own-api-key/) — connect your own model provider API keys for custom usage and billing. +* [Overages (Legacy)](/support-and-community/plans-and-billing/overages-legacy/) — information for users on legacy plans with overages enabled. +* [Pricing FAQs](/support-and-community/plans-and-billing/pricing-faqs/) — answers to common questions about plans, billing, and usage. Don’t have Warp yet? [Download Warp](https://warp.dev/download) and get started for free today. + +### Warp’s refund policies + +Please review the details of our refund policies below. To request a refund, email [**billing@warp.dev**](mailto:billing@warp.dev) with information about your situation — the more context you provide, the faster we can resolve your request. + +:::caution +In case of product defect, we require [Debugging ID](/support-and-community/troubleshooting-and-support/sending-us-feedback/#gathering-ai-debugging-id), [Logs](/support-and-community/troubleshooting-and-support/sending-us-feedback/#gathering-warp-logs), and "[Help improve Warp](/support-and-community/privacy-and-security/privacy/#how-to-disable-telemetry-and-crash-reporting)" must be enabled in order for us to identify the issue before we can provide any refunds or credits. +::: + +#### Subscription refund policy + +**Monthly plans** + +If you signed up for a monthly Warp subscription by mistake, we can issue a full refund if you cancel or downgrade within 24 hours of being charged and no credits have been used during that billing cycle. + +After 24 hours, or if credits have been used, we will cancel your subscription so that no future charges occur, and you can continue to use your plan through the end of the current billing cycle. + +**Annual plans** + +If you signed up for an annual Warp subscription by mistake, we can issue a full refund if you cancel or downgrade within 15 days of being charged and no credits have been used during that billing period. + +After 15 days, we will refund you for the remaining full months on your subscription, excluding the first month. + +#### Add-on Credits | Overages refund policy + +* If you purchased [Add-on Credits](/support-and-community/plans-and-billing/add-on-credits/) by mistake, you can receive a refund **as long as none of the credits have been used**. Warp cannot refund Add-on Credits if there has been any usage. Add-on Credits remain available for up to **12 months** from the date of purchase, as long as you have an active subscription — if you move to the Free plan, you'll lose access to any remaining Add-on Credits. +* All [Overages (Legacy)](/support-and-community/plans-and-billing/overages-legacy/) credits are **non-refundable**. Because Overages are charges for credits that were already consumed, we cannot refund resources that have already been used. + +:::caution +Warp does not offer a formal guaranteed uptime Service Level Agreement (SLA). Live incidents can be monitored on our [**Status Page**](https://status.warp.dev/), and open issues are tracked on our [**GitHub Issues**](https://github.com/warpdotdev/Warp/issues). +::: diff --git a/src/content/docs/support-and-community/plans-and-billing/pricing-faqs.mdx b/src/content/docs/support-and-community/plans-and-billing/pricing-faqs.mdx new file mode 100644 index 0000000..5fd4dad --- /dev/null +++ b/src/content/docs/support-and-community/plans-and-billing/pricing-faqs.mdx @@ -0,0 +1,352 @@ +--- +title: Pricing FAQs +description: >- + Frequently asked questions about upgrading, managing billing, refunds, and + invoicing with Warp's paid plans. +--- + +### How can I upgrade and subscribe to a Warp plan? + +All paid Warp plans come with higher monthly credit limits than the Free plan. + +When you upgrade from Free to a paid plan, your credit usage resets. If you’re switching between paid plans, any AI usage you've already accumulated will carry over. + +You can subscribe to a Warp paid plan as an individual or as part of a team. To upgrade: + +* In the app: Go to **Settings** > **Billing and usage**, then click the Upgrade link +* Online: Visit [warp.dev/pricing](https://www.warp.dev/pricing) + +After entering your payment details, you’ll receive an invoice and confirmation via email. + +### How can I get the most out of my Warp plan? + +:::caution +Warp's legacy paid plans included Pro, Turbo, and Lightspeed. + +After **Oct 30, 2025**, we have rolled out the new Build plan to replace them. Existing subscribers will start to roll over onto the Build plan starting **Dec 1st, 2025**. For questions related to the new pricing changes, please refer to [Warp's pricing change FAQs](/support-and-community/plans-and-billing/pricing-faqs/#warps-pricing-change-faqs-oct-30-2025). + +To see more details on the latest plan, please visit [**warp.dev/pricing**](https://www.warp.dev/pricing). +::: + +Warp's plans are designed for developers who rely on AI to code, debug, and move faster with their team. + +* **Build**, one usage-based plan with a set of credits, ability to Bring Your Own API Key (BYOK), and access to [Add-on credits](/support-and-community/plans-and-billing/add-on-credits/) with volume-based discounts. See more on [Bring Your Own API Key](/support-and-community/plans-and-billing/bring-your-own-api-key/). +* **Business** includes everything in Build, with advanced features like automatically enforced team-wide Zero Data Retention, SAML-based SSO, and support for teams up to 50 seats. + +Legacy plans: + +* **Pro** included higher credit limits than the Free plan, support for larger codebases with [Codebase Context](/agent-platform/capabilities/codebase-context/), and access to premium models with optional pay-as-you-go overages. +* **Turbo** included even higher credit limits, larger Codebase Context indexing, and the option to pay for additional usage beyond included credits via [Overages (Legacy)](/support-and-community/plans-and-billing/overages-legacy/). Add-on Credits were not available on this plan. +* **Pro** included higher credit limits than the Free plan, support for larger codebases with [Codebase Context](/agent-platform/capabilities/codebase-context/), and access to premium models with optional pay-as-you-go [Overages (Legacy)](/support-and-community/plans-and-billing/overages-legacy/). +* **Turbo** included even higher credit limits, larger Codebase Context indexing, and the option to pay for additional usage beyond included credits via [Overages (Legacy)](/support-and-community/plans-and-billing/overages-legacy/). Add-on Credits were not available on this plan. +* **Lightspeed** was Warp's most powerful legacy plan, offering the highest credit limits, expanded codebase indexing, access to top-tier models, and pay-as-you-go [Overages (Legacy)](/support-and-community/plans-and-billing/overages-legacy/) so you could keep working without interruption. + +For the most up-to-date feature and usage details, visit [**warp.dev/pricing**](https://www.warp.dev/pricing). + +### How can I subscribe to a Warp Enterprise plan? + +Warp offers two options for larger teams and organizations: + +* **Business Plan**: Supports up to 50 seats and is available for immediate upgrade. It includes automatically enforced team-wide Zero Data Retention by default and admin-controlled SAML-based SSO. +* **Enterprise Plan**: Offers custom pricing, credit limits, and terms. Along with support for larger engineering orgs or teams with advanced security, compliance, or support needs. + +:::tip +If you’d like to explore Enterprise, [contact our sales team](https://warp.dev/contact-sales) and someone from Warp will follow up. +::: + +### What counts as a team member and how does billing work for members? + +In Warp, a _team member_ is any seat with access to your Team — including the shared Warp Drive, Notebooks, Workflows, and other team resources. All plans allow you to invite unlimited users, but to unlock higher limits and advanced features, you’ll need to upgrade your team to a plan. Upgrading applies to your entire team, including your own account and all active members. + +On the Free plan, you can share a limited number of Notebooks and Workflows with other Free users. If your team exceeds that limit, you’ll be prompted to [upgrade to a plan](https://app.warp.dev/upgrade).\ +\ +Once you upgrade, you’ll receive email notifications as team members accept invites. Billing is **prorated**, meaning you’re only charged for the days each member has access during your billing cycle. If a member leaves mid-cycle, Warp automatically applies a credit for the unused time to your next invoice. + +**There are differences in how members are billed based on your payment schedule:** + +* **Monthly plans**: New members are billed immediately for the remaining time in the month. +* **Annual plans**: New members are billed immediately for the remaining time in the year. + +For example, if a member joins your monthly plan halfway through the month, you will be charged just half of the monthly fee ($25.00 out of $50). Similarly, if a member joins with four months remaining in an annual plan, you will be charged for those four months only, which amounts to $160 (4/12 of the annual $480). + +If a member leaves part way through the billing cycle, Warp will issue a prorated credit based on the unused portion of their membership. This credit is applied to your team's next invoice, regardless of whether you're on a monthly or annual plan. + +:::caution +All members of the team will have the same subscription plan, you can't mix and match plans for each member of a team. To have different plans, you currently must have separate teams. +::: + +### What is the value of joining or creating a team on Warp? + +Team members have access to your shared [Warp Drive](/knowledge-and-collaboration/warp-drive/) objects and limited access to Warp's collaboration features, including Session Sharing and Warp Drive storage. + +**Upgrading the team to a plan unlocks powerful collaboration and knowledge-sharing tools to help your team move faster, together:** + +* Create unlimited [Notebooks](/knowledge-and-collaboration/warp-drive/notebooks/) and [Workflows](/knowledge-and-collaboration/warp-drive/workflows/) in Warp Drive to organize and share knowledge across your team. +* Use Unlimited [Session Sharing](/knowledge-and-collaboration/session-sharing/) to collaborate in real time through live, shared terminal sessions. + +### My co-workers are using Warp but we’re not on a Team together yet. How does billing work? + +Individual users with either personal or work email domains may continue to use Warp independently without incurring billing. The benefit of joining together on a Warp Team is that you get access to a shared Team Drive and collaboration features. + +When you’re ready to use Warp more collaboratively, we suggest you nominate an Admin to [create a Team](/knowledge-and-collaboration/teams/) and invite members to join. When your Team exceeds the Warp Drive limits, you will be prompted to upgrade to a plan. + +### How does usage work if logged into the same account on multiple devices? + +When you use the account to sign into Warp on different devices, for example Linux on one computer and Windows on another, your usage of metered features like credits is tracked at the account level, not the device level. + +You can use your Warp account on multiple personal computers. Warp is designed to provide a consistent experience across devices. When you log in with the same account on different computers, your settings and preferences can be synced through the [Settings Sync](/terminal/more-features/settings-sync/) feature. + +### What happens when I downgrade during a billing cycle? + +:::caution +Note this only applies when switching between legacy plans (Pro, Turbo, Lightspeed, or the Old Business) or switching the new plans (Build, New Business). When switching between legacy to new plans, the change is immediate, prorated, and the credits are reset. See more in [What happens when I change from my legacy plan to the new Build or Business plans?](/support-and-community/plans-and-billing/pricing-faqs/#what-happens-when-i-change-from-my-legacy-plan-to-the-new-build-or-business-plans). +::: + +The subscription will downgrade to the lower plan limits at the end of the billing cycle. If you’re switching between paid plans, any AI usage you've already accumulated will carry over.\ +\ +You can downgrade at any point throughout your subscription through the billing portal by going to **Settings** > **Billing and usage** > **Manage billing**. + +### What happens when I cancel during a billing cycle? + +You can cancel at any point throughout your subscription through the billing portal by going to **Settings** > **Billing and usage** > **Manage billing**. The subscription will be canceled at the **end of your billing cycle**, monthly or yearly. + +**You can continue to use your Warp paid plan features until the cycle end date**. Any additional team members added to your team will be invoiced at the end of your billing cycle. + +### What happens if I upgrade from monthly to annual billing? + +When upgrading from a monthly to annual billing cycle the billing is prorated, meaning you only pay for the annual portion of the year you haven't paid for yet. You will be billed for the remaining part of the billing year with the discounted rate. + +You can upgrade at any point throughout your subscription through the billing portal by going to **Settings** > **Billing and usage** > **Manage billing**. + +### What happens to unused credits? + +Unused credits do not rollover to the next cycle and can't be transferred to other accounts. You see when your credits will reset in the **Settings** > **Billing and usage** menu. + +### What happens if my payment fails? + +If a payment fails, you will receive an email from Stripe and your Warp Team Settings will show a past-due alert. Certain paid plan features and the ability to invite new members will be locked down while your Team is in a past-due state. Paying the most recent invoice through the billing portal by going to **Settings** > **Billing and usage** > **Manage billing** will fully re-enable your paid plan features. + +### What counts as a credit? + +Each time you submit a prompt in Warp, whether to generate code, suggest a command, or accomplish a task, you initiate an interaction with the Agent. Please see more details in our [credits](/support-and-community/plans-and-billing/credits/) page. + +### What counts as an AI token? + +Tokens are chunks of text, such as words, parts of code, or characters, that large language models (LLMs) break down to analyze and generate responses. LLMs have a maximum number of tokens they can process at once. Credits and suggestions are not the same as tokens, which are limited separately regardless of which plan you're on. + +:::note +Warp now abstracts away token usage, so you don't need to manage or track it directly. You only need to monitor your **credit usage**, which is what’s measured against your plan limits. +::: + +If you're curious, you can read the [OpenAI article on tokens](https://help.openai.com/en/articles/4936856-understanding-tokens), or refer to the pricing page for plan-level credit allocations. If you reach your monthly credit limits on a paid plan, premium models will be temporarily disabled until your quota resets at the start of your next billing cycle. + +If you’d like to continue using premium models beyond your included quota, purchase [Add-on Credits](/support-and-community/plans-and-billing/add-on-credits/) in **Settings** > **Billing and usage** (users still on legacy Pro, Turbo, or Lightspeed plans continue to use [Overages (Legacy)](/support-and-community/plans-and-billing/overages-legacy/) until their first renewal after December 1, 2025). + +### How often do my credits reset? + +Allotted credits refill every 30 days from your signup date. When you upgrade to a [paid plan](https://www.warp.dev/pricing), you will be given more credits immediately. You can follow along with your refill period by referencing **Settings** > **Billing and usage**. Alternatively, purchase [Add-on Credits](/support-and-community/plans-and-billing/add-on-credits/), or enable auto reload with a monthly spend limit, to continue using premium models beyond your included quota. Users still on legacy Pro, Turbo, or Lightspeed plans continue to use [Overages (Legacy)](/support-and-community/plans-and-billing/overages-legacy/) until their first renewal after December 1, 2025. + +:::note +Unused credits do not rollover to the next cycle and can't be transferred to other accounts. +::: + +### Can I use a Free plan if I'm a developer at a large company or organization? + +Yes. Developers at any company size are welcome to use Warp’s Free plan. + +If you need access to advanced collaboration features or higher limits, you may benefit from upgrading to a plan, but Warp does not require large organizations to upgrade. + +### Are there any Warp discounts for students, non-profits, or open-source teams? + +Warp doesn’t currently offer discounts for students or non-profits. We recommend exploring the Free plan, which includes all core terminal features and is a great starting point for individual or community use. + +For open source teams, two paths are available: + +* The [Oz Open Source Partnership](/support-and-community/community/open-source-partnership/) program offers free Oz agent credits to high-impact open source projects. +* Warp's client itself is open source under [AGPL v3](https://github.com/warpdotdev/warp/blob/master/LICENSE), so you can build, run, and contribute to it directly. See [Contributing to Warp](/support-and-community/community/contributing/) for the flow. + +### Where is Warp Drive data for my team stored? + +Warp Drive data is securely stored on Google Cloud Platform servers located in the United States. All data is encrypted in transit and at rest. + +For more details, please [visit the Security Overview](https://www.warp.dev/legal/security) or contact [security@warp.dev](mailto:security@warp.dev). + +### What happened to the Lite model? + +Over time, the Lite model—originally designed as a fallback when premium models ran out—began to deliver inconsistent results, especially for users running complex, multi-step prompts. + +For credit-efficient usage, we encourage you to try our new **Auto (cost-efficiency) model**, which automatically selects the optimal model based on task complexity to help extend your credits. To continue AI usage please either add [Add-on Credits](/support-and-community/plans-and-billing/add-on-credits/) or consider [using your own API key](/support-and-community/plans-and-billing/bring-your-own-api-key/). + +If you have any questions or feedback, please connect with us in our [community Slack](/support-and-community/#sending-warp-feedback). + +### What payment options are available for Warp's self-service plans? + +Warp uses Stripe as our payments processor and currently accepts the following payment methods: credit card, debit card, Link, Apple Pay, Google Pay. + +We don't support ACH, checks, PayPal, cryptocurrency, or other alternative payment methods at this time. + +:::note +To checkout with Apple Pay, use the Safari browser on an Apple device.\ +To checkout with Google Pay, use Chrome, make sure you're logged into your Google Wallet account in the browser, and that "Save and fill payment methods" is enabled in the browser settings. +::: + +### How do I cancel my subscription? + +You can cancel at any point throughout your subscription through the billing portal by going to **Settings** > **Billing and usage** > **Manage billing**. + +Cancelled subscriptions will remain active until the end of the billing cycle. + +### How do I get a refund? + +For monthly subscriptions, we can issue a full refund if you cancel within 24 hours of being charged and no credits have been used. + +For annual subscriptions, we can issue a full refund within 15 days if no credits have been used, or a prorated refund for remaining months after that. Please see [Warp's Refund Policy](/support-and-community/plans-and-billing/plans-pricing-refunds/#warps-refund-policies) for full details and exceptions. + +### Why doesn't my promo code work or why was it disabled? + +Warp's promotions are a way to try Warp before committing to a subscription, not get unlimited free or inexpensive AI. To prevent abuse, we're limiting promotion codes to first-time redemptions only, so each account can only use one promotion code.\ +\ +In addition certain promo codes we issue are only valid for specific plans (not all plans) and expire after a certain time. If you apply a promo code for a certain plan, then upgrade to another plan, the promotion doesn't transfer to the new plan so you will end up paying full price for the upgrade. + +:::caution +Warp reserves the right to disable any promotion codes at any time, and cancel the associated subscriptions if we find that the code was being abused. +::: + +### How can I subscribe to Warp as tax exempt? + +Warp does allow tax exempt organizations to subscribe, but there are some additional steps that you need to take. + +1. Create a Warp account, login, and go to the [upgrade page](https://app.warp.dev/upgrade), and select a plan, but **don't checkout or pay yet.** This will only setup your billing account in the system that will be used in the later steps. +2. E-mail [billing@warp.dev](mailto:billing@warp.dev) with your proof of your organization tax exempt status and your Warp account email. +3. Warp's team will verify your tax exempt status and will change your account to tax exempt. +4. Finally, subscribe to your plan of choice. You will see no taxes applied to the bill. + +### Why can't I subscribe to Warp? + +There are certain prohibited and restricted businesses in which Stripe and major credit card networks will not process payments. For the most updated information, please see the full list [here](https://stripe.com/legal/restricted-businesses). + +### I have a question and need help. How can I reach a human at Warp? + +The team at Warp is standing by and ready to help you with any questions you have about your plan or subscription. Please email us at [billing@warp.dev](mailto:billing@warp.dev) and we will get back to you as soon as we can. + +--- + +### Warp's pricing change FAQs (Oct 30, 2025) + +For more details, see this blog post on [Warp's plan changes](https://www.warp.dev/blog/warp-new-pricing-flexibility-byok). + +#### How do I change from my current plan to the new Build or Business plan? + +You can switch to the new Warp Build or Business plan anytime from **Settings** > **Billing and usage** > **Manage billing** > **Update subscription** in the Warp app or at [app.warp.dev/upgrade](https://app.warp.dev/upgrade). Select Change plan, then choose the plan that fits your needs. + +If you take no action, your Pro, Turbo, Lightspeed, or legacy Business plan will automatically move to the new structure on your first renewal after **December 1, 2025**. You’ll receive an email before your renewal with details to make the transition easier. + +#### What happens when I change from my legacy plan to the new Build or Business plans? + +If you move from Warp’s legacy Pro, Turbo, Lightspeed, or old Business plans to the new Build or Business plans: + +* You’ll receive a prorated credit balance on Stripe for your current plan, based on how far you are into your billing cycle. This balance can be applied toward monthly Build fees or any Add-on Credits you purchase. + * You can view your credit balance by going to **Settings** > **Billing and usage** > **Manage Account**. You can also view your credit balance on the Stripe invoice that was sent when your plan changed to Build or Business. +* Your credit balance will reset to **0/1,500** when you switch to the Build or Business plan. + +If you switched immediately after the rollout, before a subsequent update was applied, we’ll retroactively reset your credit balance to 0/1,500. + +* You should see this reflected in **Settings** > **Billing and usage**. If you experience any issues, please contact us at **build-priority@warp.dev**. + +:::note +We recommend you use all the credits on your legacy plan before you switch over to the new plans. This way you can make best use of them before they are reset to the new plan limits. +::: + +:::caution +Add-on credit auto reload will be enabled by default for some legacy plan users when they transition to the Build plan. Please see more in our [Pricing FAQs](/support-and-community/plans-and-billing/pricing-faqs/#what-happens-to-my-current-plan-pro-turbo-lightspeed). +::: + +#### What should I keep in mind about this change? + +* **BYOK and Add-on credits**: These are only available on the new Build and Business plans. Switching early gives you immediate access. +* **Pricing differences**: Depending on your usage, your monthly cost may increase or decrease. You’ll now pay based on what you actually use. +* **Renewal timing**: You’ll stay on your current plan until your renewal date after December 1. No interruptions to service will occur. +* **Transparency**: You can view your credit balance, monthly spend limit, and Add-on settings anytime in **Settings** > **Billing and usage**. + +For full details, see [warp.dev/pricing](https://www.warp.dev/pricing) or reach out to billing@warp.dev if you have questions about your transition. + +#### For existing paid users: when will the new pricing take effect for my account? + +For **new customers**, the new pricing and packaging take effect immediately on Oct 30, 2025. + +For **existing monthly subscribers**, changes will apply on your first renewal after **December 1, 2025**; most likely during the month of December 2025. For **annual subscribers**, the new plan and pricing will take effect on your next renewal after December 1, 2025. + +If you have any questions, please reach out to us at **billing@warp.dev**. + +#### **What happens to my current plan (Pro, Turbo, Lightspeed, Business)?** + +You will retain your current plan and credits until the first renewal after December 1, 2025. At renewal, all current Pro, Turbo, Lightspeed, and Business plans will transition to the new Warp Build and Business plans. + +The Build and new Business plans include 1,500 monthly credits, the ability to purchase [Add-on Credits](/support-and-community/plans-and-billing/add-on-credits/) that roll over for 12 months, and the ability to bring your own API key. Learn more at [warp.dev/pricing](https://www.warp.dev/pricing). + +In addition, [Add-on credit auto reload](/support-and-community/plans-and-billing/add-on-credits/#id-2.-enable-auto-reload) will be automatically enabled for some legacy plan users in the following ways (but can be opted out of or modified at any time). Our goal is to maintain the same maximum monthly spend in line with your legacy plan subscription plus any Overages: + +* **Pro:** Will transition to the Build plan. Auto-reload _**will not**_** be enabled by default**. +* **Turbo:** Will transition to the Build plan. Auto-reload _**will**_** be enabled by default**. It will default to $30 auto-reload monthly spending limit for monthly subscribers and $22 for yearly subscribers. A handful of Turbo subscribers received a bulk discount for teams of 3 or more—please check your email for details on the default spending limits for your account. +* **Lightspeed:** Will transition to the Build plan. Auto-reload _**will**_** be enabled by default**. It will default to $205 auto-reload monthly spending limit for monthly subscribers and $182 for yearly subscribers. +* **Business:** Will transition to the new Business plan. Auto-reload _**will**_** be enabled by default**. It will default to $10 auto-reload monthly spending limit for both monthly and yearly subscribers. + +In any of the above cases, if Overages were enabled, we will set the monthly auto-reload spending limit equal to your Overage spending limit plus any of the amounts listed above.\ +\ +If your total auto-reload monthly spend limit is $80 or above, we will set the Add-on credit denomination to $20 / 1000 credits by default. If your total auto reload monthly spending limit is below $80, we will set the Add-on credit denomination to $10 / 400 credits by default. + +#### Can I continue to use Warp as my primary terminal? + +Yes, the terminal features of Warp will continue to be free to use for developers. Learn more at [Plans And Pricing](/support-and-community/plans-and-billing/plans-pricing-refunds/). + +#### How are Add-on credits different from overages? + +Add-on credits replace overages with a simpler, prepaid system. They’re up to \~40% cheaper than the old overage rates, roll over month-to-month, and remain valid for 12 months. They also come with Warp’s full SOC 2 / Zero Data Retention protection. + +#### Do credits rollover? + +For existing users on legacy plans, plan credits on Pro, Turbo, and Lightspeed do not rollover. + +For the Build plan, credits will not rollover but Add-on credits will rollover and be valid for 12 months from the date of purchase. + +#### Can I purchase Add-on Credits on legacy plans (Pro, Turbo, Lightspeed)? + +No. Add-on Credits (including auto-reload) are only available on the Build, Business, and Enterprise plans. If you attempt to purchase Add-on Credits on a legacy plan, the purchase will not go through. To access Add-on Credits, switch to the Build plan at any time from **Settings** > **Billing and usage** or at [app.warp.dev/upgrade](https://app.warp.dev/upgrade). If you need additional usage while on a legacy plan, you can use [Overages (Legacy)](/support-and-community/plans-and-billing/overages-legacy/) instead. + +#### Can I bring my own key on legacy plans (Pro, Turbo, Lightspeed)? + +No, Bring-your-own API key for OpenAI, Anthropic, and Gemini is only available to users on the Warp Build plan. You can choose to switch your existing plan to Warp Build at any time before your applicable renewal date to access BYOK. + +#### How does the monthly spend limit on Add-on Credits work? + +You set a monthly spend limit that applies to your AI usage for each calendar month. This limit acts as the maximum amount you can spend on credits during that period. + +If a purchase would exceed your limit, it won’t go through—you’ll need to either increase your limit or choose a smaller purchase amount. + +**For auto reload settings:** + +* New users who enable auto reload will start with a $200 spend limit. +* Existing paid plan users who enable auto reload will have their limit match their existing Overages spend limit (if previously configured, otherwise $200). + +#### I’m an individual developer and need more than 1,500 credits per month. What’s the right plan for me? + +If you regularly use more than 1,500 credits per month, the Build plan is designed for you. It includes 1,500 monthly credits and gives you the flexibility to scale further with Add-on Credits, which you can purchase at discounted rates directly under **Settings** > **Billing and usage**. + +Add-on Credits roll over month to month, remain valid for 12 months, and offer up to \~40% savings for larger denominations. You can also enable auto reload to automatically top up your credits when your balance runs low. + +If you’re part of a team that needs shared credit management, SSO, or enforced Zero Data Retention (ZDR), the Business plan provides all the same AI capabilities plus advanced security and administrative features. + +#### Should I subscribe to the Build plan or the Business plan? + +If you’re an individual developer or part of a small team, the Build plan is the best fit. It includes 1,500 monthly credits, discounted Add-on Credits for additional usage, and the ability to bring your own API key (BYOK) for OpenAI, Anthropic, or Google models. You’ll also get unlimited Warp Drive objects, collaboration tools, and the highest codebase indexing limits. + +If you’re part of a larger team (up to 50 members) that needs advanced administrative and security controls, choose the Business plan. It includes everything in Build, plus SSO, enforced Zero Data Retention (ZDR), shared Add-on Credits that can be used by all team members, and centralized billing – ideal for organizations that need stronger security, compliance, and team-wide management. + +#### How do credits work for multi-seat teams? + +For teams on the Build or Business plans, credits are managed at two levels: + +* **Included monthly credits**: Each seat on a paid plan receives 1,500 individual credits per month. These credits are tied to the user and reset every 30 days based on their subscription or renewal date. +* **Add-on Credits**: Once individual plan credits are used up, team members draw from a shared Add-on Credit balance that can be topped up and managed by team admins. + +This shared model gives teams the flexibility to handle variable AI usage – heavy users can consume more when needed, while the entire team benefits from shared value and volume-based discounts. diff --git a/src/content/docs/support-and-community/privacy-and-security/network-log.mdx b/src/content/docs/support-and-community/privacy-and-security/network-log.mdx new file mode 100644 index 0000000..ab8e72f --- /dev/null +++ b/src/content/docs/support-and-community/privacy-and-security/network-log.mdx @@ -0,0 +1,27 @@ +--- +title: Network Log +description: >- + Logs for all network traffic (both requests and responses) originating from + the current terminal session. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +## What is it + +You can use Warp's network log to help debug issues or simply use it to understand when information is sent or received over the network throughout a Warp session. + +Each log item is a timestamped Debug format string for either a request or response object handled by Warp. Messages are logged via pre-request and post-response hooks in Warp’s internal HTTP client. + +## How to use it + +1. To access the network log, select the Input in a session and open the [Command Palette](/terminal/command-palette/), then search for “Show Warp Network Log”. +2. That will insert a command into your Input editor - it should look something like this: `tail -f "some/path/to/warp_network.log"`. +3. Press Enter to run this command. You’ll then see the corresponding requests and responses logged in the network log. + +## How it Works + +<VideoEmbed url="https://www.loom.com/share/0d9eaeb8715846f3a96d557abe23e7ac?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Network Log Demo" /> + +## Known issues with Network Log + +At the moment, network traffic originating from crash reports and error messages is not captured in the network log. This is due to our use of the Sentry SDK, which encapsulates all network logic and doesn’t currently expose a hook for handling requests and responses directly. The team is actively investigating a solution to include such traffic in the log in a future release. You may also disable Crash Reporting entirely in Warp’s **Settings** > **Privacy** tab. diff --git a/src/content/docs/support-and-community/privacy-and-security/privacy.mdx b/src/content/docs/support-and-community/privacy-and-security/privacy.mdx new file mode 100644 index 0000000..c98745d --- /dev/null +++ b/src/content/docs/support-and-community/privacy-and-security/privacy.mdx @@ -0,0 +1,638 @@ +--- +title: Privacy +description: >- + Warp's approach to privacy and your control over your data +--- + +:::note +If you have questions, reach out at [privacy@warp.dev](mailto:privacy@warp.dev). For security-related issues, email [security@warp.dev](mailto:security@warp.dev). +::: + +## Transparency and control + +Our philosophy is complete transparency and control over any data leaving your machine. This means you can: + +* Read a complete list of [all the telemetry events](/support-and-community/privacy-and-security/privacy/#exhaustive-telemetry-table) that get sent for app analytics +* Monitor telemetry in real-time with Warp's native [Network Log](/support-and-community/privacy-and-security/network-log/) +* [Opt out](/support-and-community/privacy-and-security/privacy/#how-to-disable-telemetry-and-crash-reporting) of telemetry at any time +* Read and audit Warp's client source code at [`warpdotdev/warp`](https://github.com/warpdotdev/warp), open source under [AGPL v3](https://github.com/warpdotdev/warp/blob/master/LICENSE) + +## What telemetry data does Warp collect and why? + +Warp collects high-level telemetry and usage data to discover product quality issues and guide feature prioritization. + +If you haven't opted out of "Help improve Warp", we may collect: + +1. High level product usage and analytics data to analyze feature uptake and usage patterns. See the full list of tracked events in the [exhaustive telemetry table](/support-and-community/privacy-and-security/privacy/#exhaustive-telemetry-table) below. These are all high level metrics and do not include any user generated content. +2. AI interactions and console inputs that power our [AI features](/agent-platform/local-agents/overview/). Warp unconditionally applies [Secret Redaction](/support-and-community/privacy-and-security/secret-redaction/) in all AI interactions to ensure that any sensitive data is _never_ collected or sent to third parties. + +:::note +Telemetry must be enabled to use AI features on the Free plan, while paid plans can opt out at any time and continue using Warp, including AI. +::: + +:::caution +Business and Enterprise plans are covered by our Zero Data Retention (ZDR) agreement. No AI interaction or console data is ever collected. +::: + +Selling usage data will never be part of Warp's business model. This data is used solely to improve the end-user experience. Warp uses Sentry for crash reporting and Rudderstack for app analytics. + +You can read our [full privacy policy](https://www.warp.dev/legal/privacy-policy) as well as [how Warp handles security](https://www.warp.dev/legal/security). + +### How to disable telemetry and crash reporting + +1. Navigate to **Settings** > **Privacy**, or open the [Command Palette](/terminal/command-palette/) and search for "privacy" +2. Toggle off "Help improve Warp", "Send crash reports", or both + +![Privacy Settings](../../../../assets/support-and-community/privacy-settings-after-signup-1.png) + +With telemetry disabled, no console interactions are ever persisted on Warp's servers. Each request contains a `X-Warp-Telemetry-Enabled` header to specify whether telemetry is disabled, and even if this is missing from the request, our server assumes it's disabled. + +### Delete your account and data + +Warp provides a convenient way for you to delete your account and data. Any active Warp subscriptions associated with the account will also be cancelled when deleted. You can delete your Warp account and data in the following ways: + +* From Warp, go to **Settings** > **Privacy** > **"Visit the data management page"** + + Click the “Delete” button on the Data Management page to go through the data deletion flow. +* From the web, log in to your warp account at [https://app.warp.dev/login](https://app.warp.dev/login), then go to the data management page at [https://app.warp.dev/data\_management](https://app.warp.dev/data_management) and click the “Delete” button to go through the data deletion flow. + +:::note +Deletion jobs run every 24 hours, so if you deleted your account and want to sign up again with the same email, you won't be able to do so until that deletion job completes. +::: + +:::caution +If you're a [Team](/knowledge-and-collaboration/teams/) admin, the deletion flow will require that you assign a team member as the new admin. +::: + +### Exhaustive Telemetry Table + +| Event Name | Description | +|---|---| +| `AI Command Search opened` | Opened the modal for AI Command Search, where you can use natural language to search for commands | +| `AI Execution Profile Created` | A new AI execution profile was created | +| `AI Execution Profile Deleted` | An AI execution profile was deleted | +| `AI Execution Profile: Added To Allowlist` | An item was added to an AI execution profile allowlist | +| `AI Execution Profile: Added To Denylist` | An item was added to an AI execution profile denylist | +| `AI Execution Profile: Model Selected` | An AI model was selected for an AI execution profile | +| `AI Execution Profile: Removed From Allowlist` | An item was removed from an AI execution profile allowlist | +| `AI Execution Profile: Removed From Denylist` | An item was removed from an AI execution profile denylist | +| `AI Execution Profile: Setting Updated` | An AI execution profile setting was updated | +| `AI Input Not Sent` | The AI input was not sent | +| `AI Suggested Rule Added` | Clicked the Add Suggested Rule button in the AI blocklist | +| `AI Suggested Rule Content Changed` | Content changed by the user in the suggested rule dialog | +| `AI Suggested Rule Edited` | Clicked the Edit Suggested Rule button in the AI blocklist | +| `AIAutonomy.AutoexecutedRequestedCommand` | Autoexecuted an Agent Mode requested command | +| `AIAutonomy.ChangedAgentModeCodingPermissions` | Changed Agent Mode permissions for coding tasks | +| `AIAutonomy.ToggledAutoexecuteReadonlyCommandsSetting` | Toggled setting to autoexecute readonly Agent Mode requested commands | +| `Add Added Subshell Command` | Added a command to be automatically Warpified via Warp's subshell wrapper | +| `Add Denylisted SSH Tmux Wrapper Host` | Added a SSH host to the denylist for prompting for Tmux Wrapper | +| `Add Denylisted Subshell Command` | Explicitly prevent a command from being Warpified via Warp's subshell wrapper | +| `Add Tab With Shell` | Added a tab with specific shell | +| `Added Workflow Alias` | Added an alias to a Warp Drive workflow | +| `Agent Management View Copied Session Link` | User copied a session link from the Agent Management View | +| `Agent Management View Opened Session` | User opened a session from the Agent Management View | +| `Agent Management View Toggled` | User toggled the Agent Management View open or closed | +| `Agent Mode Query Suggestion Accepted` | Prompt Suggestion accepted | +| `Agent Mode Query Suggestions Banner Shown` | Prompt Suggestions banner shown | +| `Agent Mode Setup Banner Accepted` | Agent Mode setup banner accepted | +| `Agent Mode Setup Banner Dismissed` | Agent Mode setup banner dismissed | +| `Agent Mode Setup Project Scoped Rules Action` | User clicked a button in the Agent Mode setup project scoped rules step | +| `Agent Mode.Setup Codebase Context Action` | User clicked a button in the Agent Mode setup Codebase Context step | +| `Agent Predict` | Completed an Agent Predict prediction | +| `Agent Toolbar Dismissed` | User dismissed the use-agent toolbar | +| `AgentManagement.AgentTypeSelectorOpened` | User opened the agent type selector from agent management | +| `AgentManagement.ArtifactClicked` | User clicked an artifact button | +| `AgentManagement.CloudRunCancelled` | User cancelled a cloud run | +| `AgentManagement.CloudRunOpened` | User opened a cloud run | +| `AgentManagement.ConversationForked` | User forked a conversation | +| `AgentManagement.ConversationLinkCopied` | User copied a conversation link | +| `AgentManagement.ConversationOpened` | User opened a conversation | +| `AgentManagement.DetailsPanelContinueLocally` | User clicked Continue locally in the details panel | +| `AgentManagement.DetailsViewed` | User clicked View details | +| `AgentManagement.DismissSetupGuide` | User dismissed the ambient agent setup guide | +| `AgentManagement.FilterChanged` | User changed a filter in the management view | +| `AgentManagement.OpenSetupGuide` | User opened the ambient agent setup guide | +| `AgentManagement.SessionLinkCopied` | User copied a session link | +| `AgentManagement.SetupGuideDocsLink` | User clicked a docs URL in the setup guide | +| `AgentManagement.SetupGuideStepCopy` | User copied a workflow step from the setup guide | +| `AgentManagement.SetupGuideStepRun` | User ran a workflow step from the setup guide | +| `AgentManagement.SpawnNewCloudAgent` | User spawned a new cloud agent from agent management | +| `AgentManagement.SpawnNewLocalAgent` | User spawned a new local agent from agent management | +| `AgentManagement.TombstoneArtifactClicked` | User clicked an artifact in the tombstone view | +| `AgentManagement.TombstoneContinueLocally` | User clicked Continue locally in the tombstone | +| `AgentManagement.ViewToggled` | User toggled the agent management view open or closed | +| `AgentMode.AttachedContext` | Attached block as context to an Agent Mode query | +| `AgentMode.AttachedImages` | Attached images to an Agent Mode query | +| `AgentMode.ChangedInputType` | The input type was changed from shell -> AI or AI -> shell | +| `AgentMode.ClickedEntrypoint` | Clicked on an Agent Mode entrypoint | +| `AgentMode.Code.DiffHunksNavigated` | Agent Mode Code diff hunks navigated | +| `AgentMode.Code.DiffMatchFailed` | Failed to match code diff | +| `AgentMode.Code.FileExceededContextLimit` | File from AI exceeded context limit | +| `AgentMode.Code.FilesNavigated` | Agent Mode Code files navigated | +| `AgentMode.Code.InvalidFile` | File(s) in code diff could not be found | +| `AgentMode.Code.MalformedFinalLineProxy` | Suggested code diff likely required malformed trailing line correction (heuristic) | +| `AgentMode.Code.MissingLineNumbers` | Code diff was missing line numbers | +| `AgentMode.Code.SuggestedCodeEditedByUser` | Agent Mode Code suggestion edited by user | +| `AgentMode.Code.SuggestedEditAcceptAndContinueClicked` | User selected Accept and start conversation for a code diff suggestion in Agent Mode | +| `AgentMode.Code.SuggestedEditAcceptClicked` | User selected Accept for a code diff suggestion in Agent Mode | +| `AgentMode.Code.SuggestedEditReceived` | Agent Mode suggested a code edit | +| `AgentMode.Code.SuggestedEditResolved` | Agent Mode pending code edit suggestion resolved | +| `AgentMode.CreatedAIBlock` | Created an AI block in agent mode | +| `AgentMode.Error` | Received an error when getting Agent Mode response | +| `AgentMode.ExecutedWarpDrivePrompt` | Executed a saved prompt. | +| `AgentMode.ExitedShellProcess` | An agent-requested command caused the shell process to exit | +| `AgentMode.FileGlob.Failed` | The file glob tool failed to complete | +| `AgentMode.FileGlob.Succeeded` | The file glob tool completed successfully | +| `AgentMode.Grep.Failed` | The grep tool failed to complete | +| `AgentMode.Grep.Succeeded` | The grep tool completed successfully | +| `AgentMode.NaturalLanguageDetection.InputBufferSubmitted` | Input buffer submitted | +| `AgentMode.OpenedCitation` | Opened a citation that was surfaced in agent mode | +| `AgentMode.Orchestration.TeamAgentCommunicationFailed` | Failed to send an orchestration message or lifecycle event for a TeamAgent | +| `AgentMode.PotentialAutoDetectionFalsePositive` | Manually toggled input to shell mode after input was auto-detected as natural language. | +| `AgentMode.QueryAttemptAtLImit` | Tried to send an Agent Mode query but they already reached the query limit | +| `AgentMode.RequestRetrySucceeded` | Agent Mode request succeeded after retrying following an initial error | +| `AgentMode.SetupCreateEnvironmentAction` | User clicked a button in the Agent Mode setup create environment step | +| `AgentMode.SurfacedCitations` | Agent mode used and cited external sources that were used in its response | +| `AgentMode.ToggleAutoDetectionSetting` | Toggled the setting that enables or disables natural language auto-detection in the input. | +| `AgentNotification.Shown` | An agent notification was shown to the user (toast or mailbox) | +| `AgentTip Clicked` | User clicked a link or action in an Agent Tip | +| `AgentTip Shown` | Selected an Agent Tip to show in the Agent Mode status bar | +| `AgentView.Entered` | User entered the Agent View | +| `AgentView.Exited` | User exited the Agent View | +| `AgentView.InlineConversationMenuItemSelected` | User selected an item from the inline conversation menu | +| `AgentView.InlineConversationMenuOpened` | User opened the inline conversation menu in Agent View | +| `AgentView.ShortcutsViewToggled` | User toggled the shortcuts view in Agent View | +| `AgenticOnboarding.BlockSelected` | Selected an agentic onboarding block to execute | +| `AmbientAgent.CloudMode.Entered` | User entered cloud agent view | +| `AmbientAgent.CloudMode.EnvironmentSelector.Opened` | User opened the environment selector menu | +| `AmbientAgent.CloudMode.EnvironmentSelector.Selected` | User selected an environment from the selector | +| `AmbientAgent.CloudMode.EnvironmentSettings.GitHubAuth` | User started GitHub authentication from the environment form | +| `AmbientAgent.CloudMode.EnvironmentSettings.LaunchedAgent` | User launched an environment setup agent from the environment form | +| `AmbientAgent.ConcurrencyModal.Dismissed` | User dismissed the cloud agent capacity modal | +| `AmbientAgent.ConcurrencyModal.Opened` | User opened the cloud agent capacity modal | +| `AmbientAgent.ConcurrencyModal.UpgradeClicked` | User clicked the upgrade button in the cloud agent capacity modal | +| `AmbientAgent.DispatchFailed` | Ambient agent failed to dispatch or encountered an error | +| `AmbientAgent.EnvironmentSettings.CreatedEnvironment` | User created a new environment | +| `AmbientAgent.EnvironmentSettings.DeletedEnvironment` | User deleted an environment | +| `AmbientAgent.EnvironmentSettings.Image.Suggested` | Docker image was suggested for an environment | +| `AmbientAgent.EnvironmentSettings.Image.SuggestionFailed` | Docker image suggestion failed | +| `AmbientAgent.EnvironmentSettings.Opened` | User opened the environment management pane | +| `AmbientAgent.EnvironmentSettings.UpdatedEnvironment` | User updated an existing environment | +| `Anonymous User Attempted Login-Gated Feature` | Anonymous user attempted to access a login-gated feature | +| `Anonymous User Expiration Lockout` | An anonymous user opened Warp after their conversion deadline and was locked out | +| `Anonymous User Hit Cloud Object Limit` | Anonymous user attempted to create a cloud object past their personal object limit | +| `Anonymous User Initiated Signup` | An anonymous user initiated the sign up flow | +| `Anonymous User Linked from Browser` | Received an auth payload from anonymous user after linking in browser | +| `App Download Source` | Whether the Warp was installed from the home page or through homebrew | +| `App Startup` | App is launched | +| `Attached Workflow Alias Environment Variables` | Added or removed environment variables for a Warp Drive workflow alias | +| `Attempting to Relaunch for Update` | Attempted to relaunch the app after installing an update | +| `Auth Common Question Clicked in App` | Clicked on "Common Question" when logging in | +| `Auth: Open Privacy Settings Overlay` | Privacy settings are open during sign-in | +| `Auth: Toggle Common Questions` | Toggled FAQ Page when logging in | +| `Autosuggestion Inserted` | Accepted autosuggestion | +| `Background Block Started` | Warp created a background-output Block (whenever a processes has been backgrounded and yields some output) | +| `BaselineCommand Latency` | Command execution time | +| `Block Creation` | Created Block | +| `Block Filter Toolbelt Button Clicked` | Clicked the block filter icon in the top-right of a block | +| `Block Selection` | Selected Block | +| `Bootstrap Slow Contents` | Contents of the bootstrap block if bootstrapping is slow | +| `Bootstrapping Slow` | Slow bootstrap on session startup | +| `Bootstrapping Succeeded` | Successful bootstrap for session | +| `CLI Subagent Action Executed` | User approved a blocked action from the CLI subagent | +| `CLI Subagent Action Rejected` | User rejected a blocked action from the CLI subagent | +| `CLI Subagent Control State Changed` | Control state changed in CLI subagent (agent in control, agent blocked, user in control, or agent tagged in) | +| `CLI Subagent Input Dismissed` | User dismissed the input in the CLI subagent | +| `CLI Subagent Responses Toggled` | User toggled the visibility of agent responses in CLI subagent | +| `CLI.Execute.Agent.List` | Listed agents from the Warp CLI | +| `CLI.Execute.Agent.Profile.List` | Listed agent profiles from the Warp CLI | +| `CLI.Execute.Agent.Run` | Ran an agent from the Warp CLI | +| `CLI.Execute.Agent.RunAmbient` | Ran an ambient agent from the Warp CLI | +| `CLI.Execute.Artifact.Download` | Downloaded an artifact from the Warp CLI | +| `CLI.Execute.Artifact.Get` | Got artifact metadata from the Warp CLI | +| `CLI.Execute.Artifact.Upload` | Uploaded an artifact from the Warp CLI | +| `CLI.Execute.Conversation.Get` | Got conversation by ID from the Warp CLI | +| `CLI.Execute.Environment.Create` | Created a cloud environment from the Warp CLI | +| `CLI.Execute.Environment.Delete` | Deleted a cloud environment from the Warp CLI | +| `CLI.Execute.Environment.Get` | Got cloud environment details from the Warp CLI | +| `CLI.Execute.Environment.Image.List` | Listed available base images from the Warp CLI | +| `CLI.Execute.Environment.List` | Listed cloud environments from the Warp CLI | +| `CLI.Execute.Environment.Update` | Updated a cloud environment from the Warp CLI | +| `CLI.Execute.Federate.IssueGcpToken` | Issued a GCP federated identity token from the Warp CLI | +| `CLI.Execute.Federate.IssueToken` | Issued a federated identity token from the Warp CLI | +| `CLI.Execute.Integration.Create` | Created an integration from the Warp CLI | +| `CLI.Execute.Integration.List` | Listed integrations from the Warp CLI | +| `CLI.Execute.Integration.Update` | Updated an integration from the Warp CLI | +| `CLI.Execute.Login` | Logged in via the Warp CLI | +| `CLI.Execute.Logout` | Logged out via the Warp CLI | +| `CLI.Execute.MCP.List` | Listed MCP servers from the Warp CLI | +| `CLI.Execute.Model.List` | Listed models from the Warp CLI | +| `CLI.Execute.Provider.List` | Listed providers from the Warp CLI | +| `CLI.Execute.Provider.Setup` | Set up a provider via the Warp CLI | +| `CLI.Execute.Run.Conversation.Get` | Got run conversation from the Warp CLI | +| `CLI.Execute.Schedule.Create` | Created a scheduled agent from the Warp CLI | +| `CLI.Execute.Schedule.Delete` | Deleted a scheduled agent from the Warp CLI | +| `CLI.Execute.Schedule.Get` | Got scheduled agent configuration from the Warp CLI | +| `CLI.Execute.Schedule.List` | Listed scheduled agents from the Warp CLI | +| `CLI.Execute.Schedule.Pause` | Paused a scheduled agent from the Warp CLI | +| `CLI.Execute.Schedule.Unpause` | Unpaused a scheduled agent from the Warp CLI | +| `CLI.Execute.Schedule.Update` | Updated a scheduled agent from the Warp CLI | +| `CLI.Execute.Secret.Create` | Created a secret from the Warp CLI | +| `CLI.Execute.Secret.Delete` | Deleted a secret from the Warp CLI | +| `CLI.Execute.Secret.List` | Listed secrets from the Warp CLI | +| `CLI.Execute.Secret.Update` | Updated a secret from the Warp CLI | +| `CLI.Execute.Task.Get` | Got status of task from the Warp CLI | +| `CLI.Execute.Task.List` | Listed tasks from the Warp CLI | +| `CLI.Execute.Whoami` | Printed current user info from the Warp CLI | +| `CLIAgentFooter.ImageAttached` | User attached an image from the CLI agent footer | +| `CLIAgentFooter.SettingToggled` | User toggled the CLI agent footer setting | +| `CLIAgentFooter.Shown` | CLI agent footer was shown to the user | +| `CLIAgentFooter.VoiceInputUsed` | User used voice input from the CLI agent footer | +| `CLIAgentPlugin.ChipClicked` | User clicked the plugin install or update chip | +| `CLIAgentPlugin.ChipDismissed` | User dismissed the plugin install or update chip | +| `CLIAgentPlugin.Detected` | A CLI agent plugin was detected via a SessionStart event | +| `CLIAgentPlugin.OperationFailed` | Auto plugin install or update failed | +| `CLIAgentPlugin.OperationSucceeded` | Auto plugin install or update completed successfully | +| `CLIAgentRichInput.Closed` | CLI agent Rich Input was closed | +| `CLIAgentRichInput.Opened` | User opened CLI agent Rich Input | +| `CLIAgentRichInput.Submitted` | User submitted a prompt via CLI agent Rich Input | +| `Changed invite view option` | Toggled between link and invite for invite | +| `Clicked Continue Conversation Button` | User clicked the Continue Conversation button in a block footer | +| `Clicked Reset to Defaults Button in Settings Import` | Reset the imported settings in the settings import onboarding block | +| `Clone Repo Prompt Submitted` | User submitted a repository URL from the clone repo view | +| `Code Pane Opened` | Opened the code editor pane from various sources | +| `CodePanels.FileOpened` | Opened a file from code review, project explorer, or global search | +| `CodeReview.AddToContext` | Content added to AI context from code review | +| `CodeReview.BaseChanged` | Diff base changed in code review | +| `CodeReview.CalculateDiffMetadataFailed` | Failure when calculating diff metadata | +| `CodeReview.CommentAdded` | Inline code review comment added | +| `CodeReview.CommentDeleted` | Inline code review comment deleted | +| `CodeReview.CommentEdited` | Inline code review comment edited | +| `CodeReview.CommentEditorOpened` | Inline code review comment editor opened | +| `CodeReview.CommentListExpanded` | Inline code review comment list expanded | +| `CodeReview.CommentListItemClicked` | Inline code review comment list item clicked | +| `CodeReview.CommentRelocationFailed` | Inline code review comment relocation fell back to approximate line | +| `CodeReview.CommentResolved` | Inline code review comment resolved | +| `CodeReview.CommentsAttached` | Newly-imported comments relocated against editor lines | +| `CodeReview.CommentsReceived` | Agent insert_code_review_comments tool call received and processed | +| `CodeReview.FileSaved` | File saved in code review pane | +| `CodeReview.FindBarModeChanged` | Search mode changed in code review find bar | +| `CodeReview.FindBarToggled` | Code review find bar opened or closed | +| `CodeReview.FindNavigated` | Navigated to next or previous match in code review find bar | +| `CodeReview.LoadDiffFailed` | Failure when loading diff content | +| `CodeReview.PaneOpened` | Code review pane opened | +| `CodeReview.PaneStateChanged` | Code review pane minimized or maximized | +| `CodeReview.RevertHunkClicked` | Revert hunk button clicked | +| `CodeReview.ReviewSubmitted` | Inline code review submitted to agent | +| `CodeView.SelectionAddedAsContext` | Added selected code as context from the code editor | +| `CodexModal.Opened` | User opened the Codex modal | +| `CodexModal.UseCodexClicked` | User clicked 'Use Codex' in the Codex modal | +| `Command Correction Event` | Accepted command correction | +| `Command File Run` | Opened a .cmd or unix executable file and ran it directly in Warp | +| `Command Palette Search Accepted` | Accepted a command palette search result | +| `Command Palette Search Exited` | Exited command palette search without accepting a result | +| `Command Search Async Query Completed` | Finished searching for a command in the background | +| `Command Search Exited` | Exited command search (universal search panel to search) without accepting a result | +| `Command Search Filter Changed` | Changed command search filter | +| `Command Search Opened` | Opened command search (universal search panel to search) | +| `Command Search Result Accepted` | Accepted command search result | +| `Complete Welcome Tip` | Completed all welcome tips items | +| `Completed Settings Import` | Imported a terminal's settings via the settings import onboarding block | +| `ComputerUse.Approved` | A RequestComputerUse action was approved (manually or auto-executed) | +| `ComputerUse.Cancelled` | A RequestComputerUse action was cancelled/rejected | +| `Confirm Suggestion` | Accepted tab completion suggestion | +| `Context Menu Copy` | Clicked "Copy" in context menu | +| `Context Menu Copy Prompt` | Clicked "Copy Prompt" in context menu | +| `Context Menu Copy Selected Text` | Clicked "Copy selected text" in context menu | +| `Context Menu Insert Selected Text into Input` | Clicked "insert into input" in context menu | +| `Context Menu Toggle Git Prompt Dirty Indicator` | Toggled indicator of dirty git prompt | +| `Context Menu: Find Within Blocks` | Clicked "find within blocks" in context menu | +| `Context Menu: Initiate Block Sharing` | Opened "Share" modal via context menu | +| `Context Menu: Reinput Commands` | Clicked "reinput commands" in context menu | +| `ConversationList.ItemDeleted` | Deleted a conversation from the conversation list | +| `ConversationList.ItemOpened` | Opened a conversation from the conversation list | +| `ConversationList.LinkCopied` | Copied a conversation link from the conversation list | +| `ConversationList.Opened` | Opened the conversation list view in the left panel | +| `Copied Shared Session Link` | Copied a shared session link | +| `Copy Block Sharing Link` | Clicked "Share block..." in context menu | +| `Copy Invite Link` | Clicked "Copy Link" on Referral Modal | +| `Copy Obfuscated Secret` | Copied a secret's obfuscated contents to clipboard | +| `Copy Object To Clipboard` | Copied an object to the user's keyboard | +| `Create Custom Theme` | Created a custom theme using the built-in theme creator | +| `Create Project Prompt Submitted` | User submitted a prompt from the create project view | +| `Create Project Prompt Submitted Content` | User submitted custom prompt content from the create project view | +| `Custom Secret Regex Added` | Custom Secret Regex Added | +| `Database Read Error` | Database read error when trying to get app state for session restoration | +| `Database Startup Error` | Failed to initialize sqlite upon startup | +| `Database Write Error` | Database write error when trying to write app state for session restoration | +| `Decline Subshell Bootstrap` | Developer declined the Warp banner to Warpify the current session | +| `Delete Custom Theme` | Deleted a custom theme using the built-in theme creator | +| `Deleted Notebook` | Deleted notebook from Warp Drive team | +| `Deleted Workflow` | Deleted workflow from Warp Drive team | +| `Disable Input Sync Inputs` | Disabled / turn off the Input Synchronization (across editors) | +| `Dismiss Alias Expansion Banner` | Dismissed the banner to enable automatic alias expansion within the Input Editor | +| `Dismiss Welcome Tips` | Dismissed Welcome tips | +| `Don't Show Sharer Grant Modal Again` | When you check don't show again on the confirmation modal for granting a role | +| `Drag and Drop Tab` | Tab dragged and dropped | +| `Duplicate Object` | Cloned a Warp Drive object | +| `Edited Input Before Precmd` | Input edited before precmd hook completes | +| `Edited Workflow Alias Argument` | Edited an argument in a Warp Drive workflow alias | +| `Enable Alias Expansion From Banner` | Enabled automatic alias expansion within the Input Editor from the banner | +| `Executed Conversation Rewind` | User executed a rewind to a previous conversation state | +| `Expanded Code Suggestion` | Expanded the passive code diff suggestion | +| `Export Object` | Exported a Warp Drive object | +| `Features Page Action` | Changed settings in Features Page | +| `File Tree Toggled` | Opened the file tree/project explorer | +| `FileTree.AttachedAsContext` | Attached a file or directory as context from the file tree | +| `FileTree.ItemCreated` | Created a new file from the file tree | +| `Find Option Toggled` | Changed settings in Find Toggle | +| `Focused Config in Settings Import` | Selected a terminal in the settings import onboarding block | +| `FreeTierLimitHitInterstitial.Closed` | User closed the free tier limit hit interstitial | +| `FreeTierLimitHitInterstitial.Displayed` | The free tier limit hit interstitial was displayed | +| `FreeTierLimitHitInterstitial.UpgradeButtonClicked` | User clicked the 'Upgrade' button in the free tier limit hit interstitial | +| `Generate Block Sharing Link` | Generated Block sharing link | +| `Generate Metadata For Workflow Error` | Failed to generate metadata for a workflow using Warp AI | +| `Generate Metadata For Workflow Success` | Successfully generated metadata for a workflow using Warp AI | +| `Get Started Skip to Terminal` | User clicked skip to terminal from get started view | +| `Global Search Opened` | Opened the global search view | +| `Global Search Query Started` | Started a global search (warp_ripgrep) search | +| `ITerm Profile has Multiple Hotkeys` | Attempted to import an iTerm profile that contained multiple hotkey window bindings | +| `Identified Antivirus Software` | Identified running antivirus software on the user's machine | +| `Image Received` | Received an image through an image protocol over the pty | +| `InitialWorkingDirectoryConfigurationChanged` | Replaced the default working directory with a different path | +| `Initiate Reauth` | Started the flow to re-authenticate the client | +| `Input Mode Changed` | Changed the Input Editor Mode (Pinned to Bottom, Pinned to Top, Classic / Waterfall Mode) | +| `Input.AtMenuInteracted` | Interacted with the @ menu | +| `Input.ContextChipInteracted` | Interacted with a context chip | +| `Input.InputUXModeChanged` | Changed the input UX mode | +| `Input.VoiceInputUsed` | Used voice input | +| `InputBoxAICommandSearch` | Opened AI Command Search via the Input Editor's context menu (right clicking the buffer) | +| `InputBoxAskWarpAI` | Clicked "Ask Warp AI" from the Input Editor's context menu | +| `InputBoxCommandSearch` | Opened Command Search via the Input Editor's context menu (right clicking the buffer) | +| `InputBoxCutSelectedText` | Copied selected text from Input Editor | +| `InputBoxPaste` | Pasted text into the Input Editor's via its context menu (right clicking the buffer) | +| `InputBoxSelectAll` | Selected all the text in the Input Editor via its context menu (right clicking the buffer) | +| `Invited Teammates` | Sent emails to invite teammates to join Warp Drive team | +| `Invoked Environment Variables` | Invoked an environment variables object | +| `Isolation.DetectedIsolationPlatform` | Detected that Warp is running in an isolated sandbox | +| `Joined Shared Session` | When you join another instance of Warp using shared sessions | +| `Jumped to Bookmark Block` | Jumped to bookmarked Block | +| `Jumped to Bottom of Block Button Clicked` | Used the button to jump to the bottom of a Block | +| `Jumped to Previous Command` | Jumped to a previous command | +| `Jumped to Shared Session Participant` | Clicked on a shared session participant avatar to jump to their location in the session | +| `Keybinding Changed` | Edited a custom keybinding | +| `Keybinding Removed` | Removed / cleared a keybinding | +| `Keybinding Reset to Default` | Reset a custom keybinding to its default | +| `Knowledge Pane Opened` | Knowledge Pane Opened | +| `Linear.IssueLinkOpened` | User opened a warp://linear deeplink to work on an issue | +| `Log In Button Clicked in App` | Clicked on "Log in" button | +| `Log Out` | Logged out of the Warp client | +| `Log Out Modal Cancel Pressed` | Escaped the log out flow by canceling the log out modal | +| `Log Out Modal Shown` | When the log out modal is displayed | +| `Logged in to native app` | Login is successful | +| `Logged-out App Startup` | Started Warp in the logged-out / signed-out state | +| `Login Later Button Clicked` | Clicked "Login later" button | +| `Login Later Confirmation Button Clicked` | Clicked "Yes, skip login" confirmation button | +| `Lsp.ControlAction` | User performed an LSP control action from the footer menu | +| `Lsp.FindReferencesShown` | Find references card displayed via LSP | +| `Lsp.GotoDefinition` | User triggered goto definition via LSP | +| `Lsp.HoverShown` | Hover tooltip displayed with LSP content or diagnostics | +| `Lsp.ServerEnabled` | User enabled an LSP server for a workspace | +| `Lsp.ServerEnablementSkipped` | User skipped LSP enablement during /init | +| `Lsp.ServerFailed` | LSP server failed to start | +| `Lsp.ServerInstallCompleted` | An LSP server installation finished | +| `Lsp.ServerRemoved` | User removed an LSP server | +| `Lsp.ServerStarted` | LSP server successfully started and is available | +| `MCP Server Added` | MCP Server Added | +| `MCP Server Collection Pane Opened` | MCP Server Collection Pane Opened | +| `MCP Server Spawned` | MCP Server Spawned | +| `MCP Template Created` | MCP Template Created | +| `MCP Template Installed` | MCP Template Installed | +| `MCP Template Shared` | MCP Template Shared | +| `MCP Tool Call Accepted` | MCP Tool Call Accepted | +| `Move Active Tab` | Move active tab left or right | +| `Move Tab` | Move tab left or right | +| `Needs Reauth` | User needs to re-authenticate | +| `New Session From Directory` | Dragged a file, folder, etc. into Warp to start a session | +| `Notebook Action` | Took an action on a notebook: edit, delete, modified font size, etc. | +| `Notebook Edited` | Edited a notebook | +| `Notebook Opened` | Opened a notebook | +| `Notification Clicked` | Clicked desktop notification sent from Warp | +| `Notification Failed to Send` | Failed to send desktop notification | +| `Notification Permissions Requested` | Requested permission for desktop notification permissions | +| `Notification Request Permissions Outcome` | Recorded outcome of attempting to request desktop notification permissions | +| `Notification Sent` | Sent desktop notification | +| `Notifications Discovery Banner Action` | Showed banner introducing the notifications feature | +| `Notifications Error Banner Action` | Showed error banner for notifications feature | +| `Object Link Copied` | The web link to an object has been copied. | +| `Open Context Menu` | Opened context menu (such as right clicking, clicking on ellipses in the top right of a Block, etc.) | +| `Open Launch Config` | Opened launch config for a session | +| `Open Launch Config File` | Opened the launch config YAML file from modal once saved successfully | +| `Open Palette` | Opened the palette | +| `Open Quake Mode Window` | Toggled quake mode window when previously hidden or closed | +| `Open Repo Folder Submitted` | User selected a folder to open as a repo from the "Open repository" button | +| `Open Save Config Modal` | Opened save launch configuration modal | +| `Open Slash Menu` | Opened the slash commands menu | +| `Open Suggestions Menu` | Opened a suggestion menus, such as with up arrow or tab | +| `Open Team from URI` | Showed settings view of their newly joined team within the app | +| `Open Theme Chooser` | Opened theme chooser (list of different themes and visualizations of those themes) | +| `Open Theme Creator Modal` | Opened theme creator modal (modal to create a new theme) | +| `Open Welcome Tips` | Opened welcome tips in app | +| `Open Workflows Search` | Opened workflows search in command search pane | +| `OpenAndWarpifyDockerSubshell` | Warpifying a docker subshell from using the docker extension | +| `OpenInputBoxContextMenu` | Opened the Input Editor's context menu | +| `Opened Changelog Link` | Opened the changelog link within the App | +| `Opened Link` | Opened a highlighted link within input or output | +| `Opened Rewind Confirmation Dialog` | User opened the rewind confirmation dialog | +| `Opened Save As Workflow Modal` | Opened the modal to create a new workflow using a Block's context--command, etc. | +| `Opened Sharing Dialog` | Opened the sharing settings dialog for a session or Warp Drive object | +| `Opened Warp AI` | Activated Warp AI | +| `Opened alt screen find bar` | Opened the Find bar in the Alt Screen | +| `Page Up/Down In Editor Pressed` | Pressed `PAGE-UP` or `PAGE-DOWN` within the Input Editor | +| `Pane Drag Ended` | Ended dragging a pane via the pane header | +| `Pane Drag Inititiated` | Initiated dragging a pane via the header | +| `Parameterized Workflow With Environment Variables` | Selected from environment variables dropdown to parameterize workflow | +| `Parsed Config in Settings Import` | Parsed a terminal's settings as part of settings import | +| `Preview Pane Promoted` | Promoted a preview code tab to a normal tab | +| `Prompt Edited` | Edited the prompt using the built-in prompt editor | +| `Prompt Editor Opened` | Opened the prompt editor | +| `Pty Spawned` | Tracks the manner by which we create a new shell process (new codepath vs. old codepath). Used to ensure nothing breaks as we change parts of our infrastructure. | +| `Quit Modal Cancel Pressed` | `Cancel` button on the alert modal was pressed | +| `Quit Modal Disabled` | The quit modal dialog has been disabled and will not popup when a user closes Warp while a session is running | +| `Quit Modal Shown` | Showed an alert modal to warn the user about closing the app/window with a running process | +| `Received Subshell RC File DCS` | Spawned a subshell to be automatically Warpified | +| `Recent Menu Item Selected` | User selected an item from the recents list on the new tab zero state | +| `RemoteServer.BinaryCheck` | Remote server binary check completed (found, not found, or error) | +| `RemoteServer.ClientRequestError` | A client request to the remote server failed | +| `RemoteServer.Disconnection` | An established remote server connection was dropped | +| `RemoteServer.Initialization` | Remote server connection and initialization completed (success or failure) | +| `RemoteServer.Installation` | Remote server binary installation completed (success or failure) | +| `RemoteServer.MessageDecodingError` | A server message could not be decoded (no parseable request_id) | +| `RemoteServer.SetupDuration` | End-to-end duration of the remote server setup flow | +| `Remove Added Subshell Command` | Removed a command from the list of commands to automatically Warpify via Warp's subshell wrapper | +| `Remove Denylisted SSH Tmux Wrapper Host` | Removed an SSH host from the denylist from prompting for Tmux Wrapper | +| `Remove Denylisted Subshell Command` | Removed a command from the list of commands to IGNORE when trying to Warpify via Warp's subshell wrapper | +| `Removed Workflow Alias` | Removed an alias from a Warp Drive workflow | +| `Removed user from team` | Remove user from Warp Drive team | +| `RepoMetadata.BuildTree.Failed` | Failed to build file tree for repo metadata | +| `Resource Center Keybindings Page Opened` | Opened the keybinding page within the resource center | +| `Resource Center Opened` | Opened Resource Center pane | +| `Resource Center Tips Completed` | Completed resource center tips | +| `Resource Center Tips Skipped` | Skipped welcome tips for new users | +| `SSH Bootstrap Attempt` | Attempted bootstrapping for an SSH session | +| `SSH ControlMaster Error` | Encountered a ControlMaster error during an SSH session | +| `SSH Install Tmux Block Accepted` | User accepted an ssh install tmux block | +| `SSH Install Tmux Block Dismissed` | User dismissed an ssh install tmux block | +| `SSH Install Tmux Block Displayed` | Displayed an ssh install tmux block | +| `SSH Interactive Session Detected` | An interactive SSH session was detected | +| `SSH Remote Server Choice Do Not Ask Again Toggled` | Toggled the 'Don't ask me this again' checkbox on the SSH remote-server choice block | +| `SSH Tmux Warpification Error Block` | Ssh tmux warpification errored out | +| `SSH Tmux Warpification Succeeded` | Ssh tmux warpification succeeded | +| `SSH Tmux Warpify Block Accepted` | User accepted an ssh tmux warpify block | +| `SSH Tmux Warpify Block Dismissed` | User dismissed an ssh tmux warpify block | +| `Save Launch Config` | Saved current launch configuration of windows, tabs, and panes | +| `Select App Icon` | Selected app icon | +| `Select Command Palette Option` | Selected option from Command Palette (i.e. `⌘+P`) | +| `Select Cursor Type` | Selected cursor type | +| `Select Navigation Palette Item` | Selected session from the Session Navigation Palette (search across panes, tabs, and windows) | +| `Select Theme` | Selected theme | +| `Sent email invites` | Sent email invites for Warp Drive team | +| `Session Abandoned Before Bootstrap` | Abandoned session before the bootstrapping completes | +| `Set Line Height` | Set line height through Settings -> Appearance | +| `Set New Windows at Custom Size` | Set new windows at custom size through Settings -> Appearance | +| `Set SSH Extension Install Mode` | Changed the SSH extension install mode (always ask / always allow / always skip) | +| `Set Window Blur Radius` | Changed the blur radius from the `Settings -> Appearance` dialog | +| `Set Window Opacity` | Changed the opacity (window transparency) from the `Settings -> Appearance` dialog | +| `Settings Import Initiated` | Started the import settings flow for new users | +| `Settings.Environments.PageOpened` | User opened the Environments settings page | +| `Shared Object Limit Hit Banner View Plans Button Clicked` | Clicked the 'View Plans' button on the persistent drive banner | +| `Sharer Cancelled Grant Role` | When you cancel granting a role to a shared session participant | +| `Shell Terminated Prematurely` | The shell process terminated prematurely | +| `Show Alias Expansion Banner` | Displayed the banner asking whether Warp should automatically expand aliases within the Input Editor | +| `Show Subshell Banner` | Displayed the banner asking whether Warp should Warpify the current session via Warp's subshell wrapper | +| `Show Warpify SSH Banner` | Displayed the banner asking whether Warp should Warpify the current SSH session via Warp's SSH Wrapper | +| `ShowNotificationsDiscoveryBanner` | Showed notifications discovery banner in the block list | +| `ShowNotificationsErrorBanner` | Showed error banner for notifications feature | +| `Showed File in File Explorer` | Opened a file in Finder by using "Show in Finder" | +| `Sign Up Button Clicked in App` | Clicked "Sign Up" button | +| `Skill.Opened` | A skill was opened from an 'open skill' button or /edit-skill command | +| `Skill.Read` | A skill was read via the ReadSkill tool call | +| `Skip Onboarding Survey` | Skipped onboarding survey as a whole | +| `Slash Command Accepted` | User accepted a slash command | +| `Split Pane` | Split tab into multiple panes | +| `Static Prompt Suggestion Accepted` | Static Prompt Suggestion accepted | +| `Static Prompt Suggestions Banner Shown` | Static Prompt Suggestions banner shown | +| `Suggested Code Diff Banner Shown` | Suggested Code Diff banner shown | +| `Suggested Code Diff Failed` | Suggested Code Diff Failed | +| `Suggested Prompt Accepted` | Suggested prompt accepted | +| `Suggested Prompt Cancelled` | Suggested prompt cancelled | +| `Suggested Prompt Shown` | Suggested prompt shown | +| `Tab Creation` | Created a tab | +| `Tab Operations` | Took operation on a tab: change color, close tab, close adjacent tabs, etc. | +| `Tab Renamed` | Changed tab title | +| `Tab Single Result Autocompletion` | Accepted tab completion and inserted into Input Editor | +| `TabConfigs.ExistingConfigOpened` | User opened an existing saved tab config | +| `TabConfigs.GuidedModalOpened` | User opened the guided Create a tab config modal | +| `TabConfigs.GuidedModalSubmitted` | User submitted the guided Create a tab config modal | +| `TabConfigs.MenuCreateNewTabConfigClicked` | User clicked the New tab config entry from the tab configs menu | +| `TabConfigs.NewWorktreeConfigOpened` | User opened a new worktree config from the submenu or new worktree modal | +| `Team Created` | Created a Warp Drive team | +| `Team Joined` | Joined a Warp Drive team | +| `Team Left` | Left a Warp Drive team | +| `Team Link Copied` | Copied a Warp Drive team link | +| `Thin Strokes Setting Changed` | Changed thin strokes setting in settings -> Appearance | +| `Tier Limit Hit` | User hit the tier limit for a feature | +| `Toggle Active AI Enablement` | Toggled active AI enablement. | +| `Toggle Agent Mode Codebase Context` | Toggled on/off the enablement of codebase context usage for Agent Mode. | +| `Toggle Agent Mode Query Suggestions Setting` | Toggled on/off the prompt suggestions setting | +| `Toggle Approvals Modal` | Opened or closed teams modal | +| `Toggle Block Filter Case Sensitivity` | Toggled on/off case sensitivity within the block filter editor | +| `Toggle Block Filter Invert` | Toggled on/off invert within the block filter editor | +| `Toggle Block Filter Query` | Toggled on/off a block filter query | +| `Toggle Block Filter Regex` | Toggled on/off regex within the block filter editor | +| `Toggle Code Suggestions Setting` | Toggled on/off the code suggestions setting | +| `Toggle Codebase Context Autoindexing` | Toggled on/off the enablement of autoindexing for codebase context. | +| `Toggle Dim Inactive Panes` | Whether the dim inactive panes feature has been toggled | +| `Toggle Focus Pane On Hover` | Toggled on/off focus pane on hover feature, which causes panes to automatically focus when hovering over them | +| `Toggle Git Operations Autogen Setting` | Toggled on/off the git operations autogen setting | +| `Toggle Global AI Enablement` | Toggled global AI enablement. | +| `Toggle Intelligent Autosuggestions Setting` | Toggled on/off the intelligent autosuggestions setting | +| `Toggle Jump to Bottom of Block Button` | Enabled or disabled the Jump to Bottom of Block Button | +| `Toggle Ligature Rendering` | Toggled ligature rendering | +| `Toggle New Windows at Custom Size` | Whether the new windows at custom size feature has been toggled | +| `Toggle Obfuscate Secret` | Revealed or hid a secret | +| `Toggle Preserve Active Tab Color` | Enabled or disabled preserving the active tab color | +| `Toggle Restore Session` | Toggled session restoration ("Restore windows, tabs, panes, on startup") | +| `Toggle SSH Tmux Wrapper` | Changed the setting for SSH sessions to prompt for Tmux Wrapper | +| `Toggle SSH Warpification` | Changed the setting for SSH sessions to be Warpified | +| `Toggle Same Line Prompt` | Toggled on/off same line prompt | +| `Toggle Secret Redaction` | Toggled on/off the setting for Secret Redaction - attempts to redact secrets and sensitive information | +| `Toggle Settings Sync` | Toggle Settings Sync | +| `Toggle SharedBlock Title Generation` | Toggled on/off the shared block title generation setting | +| `Toggle Show Agent Tips` | Toggled the Show Agent Tips setting in AI settings | +| `Toggle Show Block Dividers` | Enabled or disabled the Show Block Dividers Button | +| `Toggle Sticky Command Header in Active Pane` | Expanded or collapsed the sticky command header in the active pane | +| `Toggle Sync Inputs Across All Panes in All Tabs` | Enable the synchronization of the Input Editor's buffer to all the panes in all the tabs | +| `Toggle Sync Inputs Across All Panes in Current Tab` | Enable the synchronization of the Input Editor's buffer to all the panes in the current tab | +| `Toggle Tab Indicators` | Enabled or disabled the tab indicators (failed command, etc.) | +| `Toggle Voice Input Setting` | Toggled on/off the voice input setting | +| `Toggle Warp AI` | Toggled Warp AI--an AI assistant to help you debug errors, look up forgotten commands and more | +| `Toggled Bookmark Block` | Bookmarked or unbookmarked Block | +| `Toggled Tab Bar Visibility` | Toggled when to display the tab bar | +| `Tried to Execute Before Precmd` | Attempted to execute command before precmd, a shell stage that has metadata on a command such as ssh, prompt info, etc. | +| `Trigger Subshell Bootstrap` | Attempted to Warpify the current session via Warp's subshell wrapper | +| `Triggered Command XRay` | Triggered Command X-Ray (hovering over a command for explanation) | +| `Unable to Update To New Version` | Update available but not authorized to install | +| `Undo Close` | Re-opened a closed tab or window (undo closing a tab or window) | +| `Unhandled Editor Modifier Key` | Used modifier keybinding keystroke which is not currently supported | +| `Unsupported Shell` | Booted Warp with a shell that isn't supported | +| `Update Block Filter Query` | When a new filter is applied to a block | +| `Update Block Filter Query With Context Lines` | When the number of context lines for a block filter query is updated | +| `Update Tab Close Button Position` | Updated the tab close button position | +| `Updated Alt Screen Padding Mode` | Updated the custom padding setting for the alt-screen | +| `Updated Sorting Choice` | Modified the sorting scheme for Warp Drive objects | +| `UseAgentToolbar.SettingToggled` | User toggled the Use Agent footer setting | +| `Used Warp AI Prepared Prompt` | Used one of the Warp-provided prompts, like "Show examples" | +| `User Initiated Closing Something` | Attempted to either quit the app or close a window | +| `User Initiated Log Out` | Confirms a user has explicitly logged out of the application | +| `User Menu Upgrade Clicked` | Clicked the 'Upgrade' menu item in the user menu | +| `VerticalTabs.DiffStatsChipClicked` | User clicked a diff stats chip in the vertical tabs panel or detail sidecar | +| `VerticalTabs.DisplayOptionChanged` | User updated a display option in the vertical tabs settings popup | +| `VerticalTabs.PrChipClicked` | User clicked a GitHub PR chip in the vertical tabs panel or detail sidecar | +| `Vim Keybindings Banner Dismissed` | Dismissed the banner to enable Vim keybindings in the Input Editor | +| `Vim Keybindings Banner Displayed` | Displayed the banner asking whether Warp should enable Vim keybindings in the Input Editor | +| `Vim Keybindings Enabled from Banner` | Enabled Vim keybindings in the Input Editor from the banner | +| `Warp AI Action` | Executed a Warp AI action: Restart, Copy, Insert into terminal | +| `Warp AI Character Limit Exceeded` | Attempted to ask a question longer than 1k chars to Warp AI | +| `Warp AI Request Issued` | Issued a question to Warp AI | +| `Warp Drive Opened` | Opened Warp Drive panel | +| `Warp Drive Sharing onboarding block shown` | Showed onboarding block for Warp Drive sharing | +| `Warp Drive object opened on desktop` | Warp Drive object on the web was opened on the desktop | +| `Warpify Footer Accepted Warpify` | User clicked Warpify in the warpify footer | +| `Warpify Footer Shown` | Displayed the warpify footer for a detected subshell or SSH session | +| `Web session opened on desktop` | Shared session viewed on the web was opened on the desktop | +| `Workflow Executed` | Executed workflow | +| `Workflow Selected` | Selected workflow and populated into the Input Editor | +| `Zero State Prompt Suggestion Used` | Used a zero state prompt suggestion | +| `experiments.client.enroll_client` | Client assigned to A/B test | +| `onboarding_agent_slide_upgrade_clicked` | User clicked the Upgrade button on the Customize your agent slide | +| `onboarding_callout_completed` | User completed the callout flow | +| `onboarding_callout_displayed` | A callout was displayed to the user | +| `onboarding_callout_next` | User clicked next on a callout | +| `onboarding_folder_selected` | User selected a folder | +| `onboarding_folder_selection_started` | User started folder selection | +| `onboarding_free_user_no_ai_upgrade_clicked` | User clicked the upgrade button on the free-user no-AI experiment slide | +| `onboarding_get_started_clicked` | User clicked the Get Started button | +| `onboarding_setting_changed` | User changed a setting during onboarding | +| `onboarding_slide_navigated_back` | User navigated to the previous slide | +| `onboarding_slide_navigated_next` | User navigated to the next slide | +| `onboarding_slide_viewed` | User viewed a slide in the onboarding flow | +| `onboarding_slides_completed` | User completed the onboarding slides | +| `onboarding_started` | User started the onboarding flow | +| `onboarding_welcome_login_clicked` | User clicked the Log in link on the welcome/intro slide | +| `perf_metrics.memory_usage_high` | Total application memory usage exceeded a significant threshold | +| `perf_metrics.resource_usage` | Periodic report on application resource usage statistics | +| `revenue.AutoReloadModalClosed` | User closed the auto-reload modal (either dismissed or enabled auto-reload) | +| `revenue.AutoReloadToggledFromBillingSettings` | User toggled auto-reload in Billing & Usage settings | +| `revenue.OutOfCreditsBannerClosed` | User closed the 'Out of credits' banner (dismissed or purchased credits) | + diff --git a/src/content/docs/support-and-community/privacy-and-security/secret-redaction.mdx b/src/content/docs/support-and-community/privacy-and-security/secret-redaction.mdx new file mode 100644 index 0000000..94131b6 --- /dev/null +++ b/src/content/docs/support-and-community/privacy-and-security/secret-redaction.mdx @@ -0,0 +1,56 @@ +--- +title: Secret Redaction +description: >- + Secret Redaction automatically redacts secrets and sensitive data in + terminal Secret Redaction attempts to redact secrets and sensitive data in + your Secret Redaction detects and redacts secrets, passwords, API keys, IP + addresses, and PII in your terminal output. +--- + +## How to access it + +Disabled by default, to enable Secret Redaction open **Settings** > **Privacy** > **Secret redaction** or type in "Secret Redaction" to toggle it in the [Command Palette](/terminal/command-palette/). + +## How it works + +Secret Redaction attempts to detect sensitive data (including secrets, passwords, API keys, and PII) using your list of regex patterns. Any identified secret will be redacted instead of being sent to our servers or any LLM provider. Additionally, Warp Drive will prevent you from saving any secrets in plain text (workflows, MCP servers, prompts, etc.).\ +\ +Warp ships with a [list of recommended regex](/support-and-community/privacy-and-security/secret-redaction/#secret-regex-list) you can easily add to the list. Additionally you can add custom regex for secrets you want to include in **Settings** > **Privacy** > **Secret redaction** > **Custom secret redaction**. + +## Visually hiding secrets + +By default, identified secrets will be displayed with a strikethrough visual treatment, i.e. ` echo`` `` `~~`password`~~. + +If instead you'd prefer to visually hide the secrets as well, i.e. `echo ********`, the setting to obfuscate secrets with asterisks can be found in **Settings** > **Privacy** > **Secret redaction** > **Hide secrets in blocklist**. + +Clicking on a secret will display a tooltip that lets you reveal the secret or copy the secret's contents. When trying to copy terminal output containing secrets, it will be copied as asterisks (e.g. `echo password` becomes `echo ********`) unless revealed or copied from the tooltip. Secret redaction is not applied in [Session Sharing](/knowledge-and-collaboration/session-sharing/). + +## Case sensitivity + +Secret redaction regexes are case-sensitive by default (i.e. the regex `password` will not match the text `Password`). If you want a regex to be case-sensitive, you can prepend `(?i)` like so: `(?i)password` to ensure that `PASSWORD`, `Password`, and `password` would all match. + +## Secret regex list + +Here is a list of the recommended regular expressions that Warp uses to identify secrets: + +| Secret Type | Regex Pattern | +| ----------------------------------------- | ----------------------------------------------------------------------------------------- | +| IP V4 Address | `\b((25[0-5]\|(2[0-4]\|1\d\|[1-9]\|)\d)\.?\b){4}\b` | +| IP V6 Address | `\b((([0-9A-Fa-f]{1,4}:){1,6}:)\|(([0-9A-Fa-f]{1,4}:){7}))([0-9A-Fa-f]{1,4})\b` | +| Slack App Token | `\bxapp-[0-9]+-[A-Za-z0-9_]+-[0-9]+-[a-f0-9]+\b` | +| Phone Number | `\b(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}\b` | +| AWS Access ID | `\b(AKIA\|A3T\|AGPA\|AIDA\|AROA\|AIPA\|ANPA\|ANVA\|ASIA)[A-Z0-9]{12,}\b` | +| MAC Address | `\b((([a-zA-z0-9]{2}[-:]){5}([a-zA-z0-9]{2}))\|(([a-zA-z0-9]{2}:){5}([a-zA-z0-9]{2})))\b` | +| Google API Key | `\bAIza[0-9A-Za-z-_]{35}\b` | +| Google OAuth ID | `\b[0-9]+-[0-9A-Za-z_]{32}\.apps\.googleusercontent\.com\b` | +| GitHub Classic Personal Access Token | `\bghp_[A-Za-z0-9_]{36}\b` | +| GitHub Fine Grained Personal Access Token | `\bgithub_pat_[A-Za-z0-9_]{82}\b` | +| GitHub OAuth Access Token | `\bgho_[A-Za-z0-9_]{36}\b` | +| GitHub User to Server Token | `\bghu_[A-Za-z0-9_]{36}\b` | +| GitHub Server to Server Token | `\bghs_[A-Za-z0-9_]{36}\b` | +| Stripe Key | `\b(?:r\|s)k_(test\|live)_[0-9a-zA-Z]{24}\b` | +| Firebase Auth Domain | `\b([a-z0-9-]){1,30}(\.firebaseapp\.com)\b` | +| JSON web token | `\b(ey[a-zA-z0-9_\-=]{10,}\.){2}[a-zA-z0-9_\-=]{10,}\b` | +| OpenAI API Key | `\bsk-[a-zA-Z0-9]{48}\b` | +| Anthropic API Key | `\bsk-ant-api\d{0,2}-[a-zA-Z0-9\-]{80,120}\b` | +| Fireworks API Key | `\bfw_[a-zA-Z0-9]{24}\b` | diff --git a/src/content/docs/support-and-community/troubleshooting-and-support/known-issues.mdx b/src/content/docs/support-and-community/troubleshooting-and-support/known-issues.mdx new file mode 100644 index 0000000..174c38f --- /dev/null +++ b/src/content/docs/support-and-community/troubleshooting-and-support/known-issues.mdx @@ -0,0 +1,319 @@ +--- +title: Known Issues +description: >- + Known Warp issues with workarounds, including SSH, shells, and incompatible + tools. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +:::note +To see a complete list of Warp issues and feature requests, please visit our [GitHub issues page](https://github.com/warpdotdev/Warp/issues?q=is%3Aissue+is%3Aopen+sort%3Acreated-desc). + +Please note that there are tools that are incompatible with Warp, as listed [below](/support-and-community/troubleshooting-and-support/known-issues/#list-of-incompatible-tools). You can find debugging information in this [section](/support-and-community/troubleshooting-and-support/known-issues/#debugging). +::: + +## General + +### SSH + +To enable Blocks over SSH, Warp uses an SSH Wrapper function; navigate to settings > features if you need to disable it. Please see [Troubleshooting Legacy SSH](/terminal/warpify/ssh-legacy/#troubleshooting-ssh) for more info on workarounds to SSH issues, or see the [new SSH Page](/terminal/warpify/ssh/) for more on the upcoming features. + +### Online features don't work + +There is a known issue that can occur that causes online features to break ([Oz agent](/agent-platform/local-agents/overview/), [Generate](/agent-platform/local-agents/overview/), [Block Sharing](/terminal/blocks/block-sharing/), [Refer a Friend](/support-and-community/community/refer-a-friend/) ). This is due to the login token going stale, typically due to a password change, and can be resolved by the following steps: + +<Tabs> + <TabItem label="macOS"> + 1. Remove Warp user login with the following command: + + ```bash + sudo security delete-generic-password -l "dev.warp.Warp-Stable" $HOME/Library/Keychains/login.keychain + ``` + + 2. [Login to Warp](/getting-started/quickstart/installation-and-setup/#log-in-to-warp-optional) + </TabItem> + <TabItem label="Windows"> + 1. Remove any user files with the following command: + + ```powershell + Remove-Item $env:LOCALAPPDATA\warp\Warp\data\*-User + ``` + + 2. [Login to Warp](/getting-started/quickstart/installation-and-setup/#log-in-to-warp-optional) + </TabItem> + <TabItem label="Linux"> + 1. Remove Warp user login with your keychain manager (gnome-keyring, kwallet, etc.). Search for `dev.warp.Warp` and delete the `User` password/secret. + 2. Remove any user files with the following command: + + ```bash + rm -f ${XDG_STATE_HOME:-$HOME/.local/state}/warp-terminal/*-User + ``` + + 3. [Login to Warp](/getting-started/quickstart/installation-and-setup/#log-in-to-warp-optional) + </TabItem> +</Tabs> + +### English-only UI + +Nov 2021: We have added character support for Chinese, Korean, and Japanese, but our UI currently only supports English. + +### Abnormal rendering of Chinese characters + +If you notice issues with the terminal rendering Chinese characters (i.e. [#3366](https://github.com/warpdotdev/Warp/issues/3366)). Please try adding the following lines to your rc file. + +``` +export LC_ALL=zh_CN.UTF-8 +export LANG=zh_CN.UTF-8 +``` + +### Warp fails to render a window + +This can likely occur due to some corruption in the local sqlite db. You may see a similar error your [logs](/support-and-community/#gathering-warp-logs): + +``` +[WARN] SQLite error 283 (A WAL mode database file was recovered): recovered 383 frames from WAL file /home/xxxxx/.local/state/warp-terminal/warp.sqlite-wal +``` +To try and resolve the issue of Warp not rendering a window, rename the SQLite database found in the [following locations](/terminal/sessions/session-restoration/#session-restoration-database). + +### Misc. + +* When you [SSH](/support-and-community/troubleshooting-and-support/known-issues/#ssh), we start a bash shell on the remote host. We built a wrapper around SSH to make Warp features possible. +* If your default shell is zsh, your aliases typically do not transfer over. Other shells are unsupported for now. +* When you open a [non-shell-based subshell (REPL)](https://github.com/warpdotdev/Warp/issues/4082), Warp does not modify the environment — it behaves like a standard terminal session. +* Warp may become unresponsive if it doesn't have permission to access the folders. +* [No touch input support](https://github.com/warpdotdev/Warp/issues/5347) + +## Agent Mode + +* Note that Agent Mode blocks are not shareable during [session sharing](/knowledge-and-collaboration/session-sharing/). Participants will be able to share regular shell commands that are run, but will not be able to share AI interactions (requested commands, AI blocks, etc.). +* Block actions such as [Block Sharing](/terminal/blocks/block-sharing/) are not available on Agent Mode AI blocks. +* Agents do not have up-to-date information on several commands’ completion specs +* Agent Mode works better with Warp's default prompt settings, where the prompt starts on a new line, than it does with a same-line prompt. If you are using the same-line prompt, the cursor will jump from the end of the single line to the start of the input box when you switch to Agent Mode. + +## Shells + +### fish shell `read` command + +There is an issue in fish shell version 3.6 and below that causes the `read` built-in command to break Warp's integration with fish. This means that using `read` directly or any fish scripts that call `read` will not work as expected in Warp. That issue is resolved in the fish repository and so should be fixed in the next release of fish itself. We recommend upgrading fish to the most recent version to resolve this issue. + +### Warp shell loads slowly due to EDR + +If you comment out the rc files (i.e. `~/.zshrc`, `~/.bashrc`, `~/.config/fish/config.fish`), and still notice a slowdown on loading the shell, it is likely due to an Endpoint Detection and Response or EDR (i.e. Sentinel One, CrowdStrike, Carbon Black) causing the issue. Please restart your system and see if the issue persists. If so, please [Send us Feedback](/support-and-community/) and provide details of your EDR, OS, shell, etc. + +### Configuring and debugging your RC files + +To support Blocks ([custom hooks](https://blog.warp.dev/how-warp-works/#implementing-blocks)), a native Input Editor experience, AI blocks, etc. we have built custom support for a subset of shell functionality (decouple functionality from the shell and move to the terminal). This leads to Warp being incompatible with various tools and plugins. Please see the [list of incompatible](/support-and-community/troubleshooting-and-support/known-issues/#list-of-incompatible-tools) tools to find the tools that are known not to work with Warp. + +Unlike typical terminals which are essentially continuous character grids, each section of Warp is its own (separate) UI element. Please see our [Prompt](/terminal/appearance/prompt/) page for more information on custom prompts. + +#### Debugging + +If Warp is not working with your dotfile configuration, you can run your shell in Warp with a clean configuration using examples below: + +<Tabs> + <TabItem label="bash"> + You can set up clean configs for Bash (Bourne Again SHell) by moving or commenting out your `.bashrc`\ + \ + If Warp starts working correctly then Warp is incompatible with something in the current dotfiles. We can isolate what is incompatible by iteratively disabling sections of our dotfiles with the `WarpTerminal` flag until we find the culprit. See the list of incompatible tools below and comment them out just for Warp with the following conditionals: + + ```bash +# bash (See ~/.bashrc) + if [[ $TERM_PROGRAM != "WarpTerminal" ]]; then + ##### WHAT YOU WANT TO DISABLE FOR WARP - BELOW + # Unsupported plugin/prompt code here, i.e. + ##### WHAT YOU WANT TO DISABLE FOR WARP - ABOVE + fi +``` + </TabItem> + <TabItem label="zsh"> + You can set up clean configs for Zsh (Z SHell) by moving or commenting out your `.zshrc`\ + \ + If Warp starts working correctly then Warp is incompatible with something in the current dotfiles. We can isolate what is incompatible by iteratively disabling sections of our dotfiles with the `WarpTerminal` flag until we find the culprit. See the list of incompatible tools below and comment them out just for Warp with the following conditional: + + ```bash + # zsh (See ~/.zshrc) + if [[ $TERM_PROGRAM != "WarpTerminal" ]]; then + ##### WHAT YOU WANT TO DISABLE FOR WARP - BELOW + # Unsupported plugin/prompt code here + ##### WHAT YOU WANT TO DISABLE FOR WARP - ABOVE + fi + ``` + </TabItem> + <TabItem label="fish"> + You can set up clean configs for Fish (Friendly Interactive SHell) by moving or commenting out your `config.fish`\ + \ + If Warp starts working correctly then Warp is incompatible with something in the current config file. We can isolate what is incompatible by iteratively disabling sections of our config file with the `WarpTerminal` flag until we find the culprit. See the list of incompatible tools below and comment them out just for Warp with the following conditional: + + ```bash + # fish (see ~/.config/fish/config.fish) + if test "$TERM_PROGRAM" != "WarpTerminal" + ##### WHAT YOU WANT TO DISABLE FOR WARP - BELOW + # Unsupported plugin/prompt code here + ##### WHAT YOU WANT TO DISABLE FOR WARP - ABOVE + end + ``` + </TabItem> + <TabItem label="pwsh"> + You can set up clean configs for pwsh (PowerShell) by moving or commenting out your `$PROFILE` + + If Warp starts working correctly then Warp is incompatible with something in the current profile. We can isolate what is incompatible by iteratively disabling sections of our profile with the WarpTerminal flag until we find the culprit. See the list of incompatible tools below and comment them out just for Warp with the following conditional: + + ```powershell +# pwsh (see $PROFILE) + if ($env:TERM_PROGRAM -ne "WarpTerminal") { + ##### WHAT YOU WANT TO DISABLE FOR WARP - BELOW + # Unsupported plugin/prompt code here + ##### WHAT YOU WANT TO DISABLE FOR WARP - ABOVE + } +``` + </TabItem> +</Tabs> + +#### List of incompatible tools + +The following non-exhaustive list of plugins, prompts, or tools can cause potential issues in Warp: + +* oh-my-fish, oh-my-bash, or other unsupported shell prompts. See our [Custom Prompt Compatibility Table](/terminal/appearance/prompt/#custom-prompt-compatibility-table). +* [iterm shell integration](https://iterm2.com/documentation-shell-integration.html) + * `test -e "${HOME}/.iterm2_shell_integration.zsh" && source "${HOME}/.iterm2_shell_integration.zsh" || true` +* [Termium](https://codeium.com/blog/termium-codeium-in-terminal-launch) + * `eval "$(termium shell-hook show pre)"` + * `eval "$(termium shell-hook show post)"` +* [thefuck experimental instant mode](https://github.com/nvbn/thefuck?tab=readme-ov-file#experimental-instant-mode) + * `eval $(thefuck --alias --enable-experimental-instant-mode)` +* [fubectl](https://github.com/kubermatic/fubectl) + * `[ -f ${HOME}/bin/fubectl.source ] && source ${HOME}/bin/fubectl.source` +* [BIND keys](https://github.com/warpdotdev/Warp/issues/537) + * `bindkey '^j' down-line-or-beginning-search`, which causes users to have to hit ENTER twice to run a command. + * `bindkey 'tab' autosuggest-accept`, which causes incorrect behavior with autocompletion. +* `z`, `compdef`, `compinit`, [prezto utility module](https://github.com/sorin-ionescu/prezto/blob/master/modules/utility/README.md), [bash-it](https://github.com/Bash-it/bash-it), CodeWhisperer or other [shell-based completion](https://github.com/warpdotdev/Warp/discussions/434) plugins. +* OH-MY-ZSH Themes + * e.g. avit, spaceship, maybe more ... +* OH-MY-ZSH Plugins + * e.g. zsh-autosuggestions, zsh-autocomplete, maybe more ... +* Oh-My-Tmux +* zsh4h (ZSH for Humans) +* znap +* FZF +* `[[ -r "/usr/local/etc/profile.d/bash_completion.sh" ]] && "/usr/local/etc/profile.d/bash_completion.sh"` +* `eval "$(rbenv init -)"` +* `grml-zsh-config` +* Python virtual environment PS1 [settings](https://github.com/warpdotdev/Warp/issues/2713#issuecomment-1447129449) +* [Starship settings](/terminal/appearance/prompt/#starship-settings) +* `zle-line-init` +* Potentially more — this is a non-exhaustive list. If you find an incompatible tool, please email us at [feedback@warp.dev](mailto:feedback@warp.dev) + +## Operating systems + +<Tabs> + <TabItem label="macOS"> + **SSH to local network device is denied on macOS** + + On macOS, you may be [denied permission to SSH](https://github.com/warpdotdev/Warp/issues/5550) from Warp into other devices in your local network and see an error like: `ssh: connect to host <host_name> port 22: Undefined error: 0`.\ + To resolve this issue, go to  > **System Settings** > **Privacy & Security** > **Local Network** and add Warp. + + ![macOS SSH permission error](../../../../assets/support-and-community/mac-ssh-permission.png) + + **Unexpected loss of permission on macOS** + + On macOS, you may see an `Operation not permitted` error when trying to run commands in directories that have already been granted macOS permissions (Documents, Downloads, Desktop, etc). The best workaround at this time is to [apply any pending updates](/support-and-community/troubleshooting-and-support/updating-warp/) so that the new Warp binary has the correct permissions. We are tracking this issue [here](https://github.com/warpdotdev/Warp/issues/3009). + + ![Permission error on macOS](../../../../assets/support-and-community/permission-error-macos.png) + + **Auto-Update error on macOS** + + Warp may have an error opening after auto-update on macOS Ventura. This issue has been resolved for current and future releases of Warp. To avoid the issue, [update Warp](/support-and-community/troubleshooting-and-support/updating-warp/) _before_ you upgrade to macOS Ventura.\ + \ + If you experience an error opening Warp, please try the following: + + * Go to the macOS Applications folder, right-click on Warp, choose Open, then the '"Warp" is damaged' dialog will have the option to click the Open button. + + <DemoVideo src="/assets/support-and-community/open-warp-mac.mp4" label="Right-clicking Warp in the macOS Applications folder and choosing Open to bypass the damaged app dialog" /> + + * If the above doesn't work, [uninstall Warp](/support-and-community/troubleshooting-and-support/logging-out-and-uninstalling/), then [re-install Warp](/getting-started/quickstart/installation-and-setup/). + + **Running x86 commands with macOS** + + In some cases, CLI applications only work on x86, so you can run Warp with Rosetta on macOS to be able to use them by doing the following. + + * Go to **Finder** > **Applications** and search for Warp. + * Right-click and select Get Info. + * Then check the box on Open with Rosetta. + </TabItem> + <TabItem label="Windows"> + **Unsupported in Warp on Windows** + + The following features are not supported in Warp on Windows. Please track the relevant GitHub issues linked below for any changes: + + * [cmd.exe](https://github.com/warpdotdev/Warp/issues/5882) or [fish](https://github.com/warpdotdev/Warp/issues/6060) shells + + **Warp won't run on Windows** + + We're tracking some issues on Windows where [Warp crashes on startup](https://github.com/warpdotdev/Warp/issues/5840) or doesn't render, with some possible workarounds below. If none of the workarounds help, please open a [new GitHub issue](https://github.com/warpdotdev/warp/issues/new/choose) and include [logs](/support-and-community/#gathering-warp-logs), installation (Baremetal or VM, x86\_64 or ARM64), and the issue you had. + + * Graphics + * You can select the graphics backend used to render new Warp windows in the Settings menu, under **Features** > **System** > **Preferred graphics backend**. + * You can also opt to render new Warp windows with an integrated GPU, under **Features** > **System** > **Prefer rendering new windows with integrated GPU (low power)**. + + **Crash on opening a Launch configuration or doesn't become transparent on Windows** + + When a user has an Nvidia 572.xx or AMD 23.10.x drivers or above, Warp may [crash when trying to open a Launch Configuration](https://github.com/warpdotdev/Warp/issues/5875), or [Warp fails to become transparent](https://github.com/warpdotdev/Warp/issues/5903) (opacity setting doesn't work). These are known limitations of the graphics drivers. We're investigating the issues and will update the GitHub issues above. You can workaround this by forcing the graphics backend to Vulkan or OpenGL by running the following from another terminal and setting your GPU driver Vulkan/OpenGL render method setting to "Prefer Native", or using the [DX12 backend](/support-and-community/troubleshooting-and-support/known-issues/#warp-wont-run-or-render-on-windows): + + ```powershell + # Run if Warp on Windows is installed for a single user + $env:WGPU_BACKEND="vulkan,gl"; & "$env:LOCALAPPDATA\Programs\Warp\warp.exe" + + # Run if Warp on Windows is installed for all users + $env:WGPU_BACKEND="vulkan,gl"; & "$env:PROGRAMFILES\Warp\warp.exe" + ``` + </TabItem> + <TabItem label="Linux"> + **Warp won't run on Linux** + + We're tracking some issues on Linux where a [Warp window doesn't show/render](https://github.com/warpdotdev/Warp/issues/4215) and won't run in [Virtual Machines](https://github.com/warpdotdev/Warp/issues/4476), over [remote desktops](https://github.com/warpdotdev/Warp/issues/4435), or on [WSL](https://github.com/warpdotdev/Warp/issues/4240). Some possible workarounds are below. If none of the workarounds help, please open a [new GitHub issue](https://github.com/warpdotdev/warp/issues/new/choose) and include [logs](/support-and-community/#gathering-warp-logs) with your Linux distro, installation (WSL, Baremetal or VM, x86\_64 or ARM64), and the issue you had. + + :::note + * Many package install examples are for Ubuntu using `apt`, your distro may use different commands (`dnf`, `pacman`, `zypper`) or package names. + * GPU Drivers and Default GPU / Graphics API environment variables are system-dependent, e.g. AMD vs NVIDIA and OpenGL vs Vulkan. + ::: + + * System + * Installing or Updating [Xorg](https://www.x.org/wiki/) / [Wayland](https://wayland.freedesktop.org/): `sudo apt install xserver-xorg` / `sudo apt install wayland` + * Installing [Hack font](https://sourcefoundry.org/hack/) on WSL and VMs: `sudo apt install fonts-hack` + * Install [WSL utilities](https://github.com/wslutilities/wslu): `sudo apt install wslu` + * Install Mesa utilities: `sudo apt install mesa-utils` + * Install Mesa Vulkan drivers: `sudo apt install mesa-vulkan-drivers` + * If unable to use the file picker: `sudo apt install xdg-desktop-portal xdg-desktop-portal-gtk zenity` + * If unable to copy-paste: `sudo apt install wl-clipboard` + * Graphics + * Install or Update your GPU driver: e.g. [NVIDIA](https://github.com/warpdotdev/Warp/issues/4215#issuecomment-1969750786) 535.x or below drivers + * For Ubuntu: `sudo ubuntu-drivers install` + * For Fedora: `sudo dnf install akmod-nvidia` + * For Arch Linux: `sudo pacman -S nvidia` + * For openSUSE: `sudo zypper install x11-video-nvidiaG05` + * Use [Low Power (integrated) GPU](https://github.com/warpdotdev/Warp/issues/4215#issuecomment-1967500574) in `~/.config/warp-terminal/user_preferences.json` file: `{"prefs":{"PreferLowPowerGPU": "true",}}`. The low-power workaround is particularly helpful if you see [`Unrecognized device error ERROR_INITIALIZATION_FAILED` in warp.log](https://github.com/warpdotdev/Warp/issues/4390#issuecomment-1989493913). + * Environmental Variables + * Prefix `warp-terminal` with the variables (multiple can be used), and once you confirm they work, `export` them in your `.profile`/`.zprofile` to [load on startup](https://github.com/warpdotdev/Warp/issues/4240#issuecomment-1968228029): + * [Default to Wayland](https://github.com/warpdotdev/Warp/issues/4240#issuecomment-1961993281): `WARP_ENABLE_WAYLAND=1` + * Set [Default GPU](https://docs.mesa3d.org/drivers/d3d12.html#utilities) for WSL: e.g. `MESA_D3D12_DEFAULT_ADAPTER_NAME=NVIDIA` + * Set [Graphics APIs](https://github.com/gfx-rs/wgpu?tab=readme-ov-file#environment-variables): e.g. `WGPU_BACKEND=gl` + + **Update fails after upgrading Linux** + + Some Linux distros may modify Warp's package repository during the OS upgrades. We're aware of this on Ubuntu, but this may affect other Linux distros. We're tracking this issue on GitHub [here](https://github.com/warpdotdev/Warp/issues/5201).\ + \ + To workaround this issue, manually add the repository to update Warp. The Ubuntu example is below: + + ``` + sudo apt-get install wget gpg + wget -qO- https://releases.warp.dev/linux/keys/warp.asc | gpg --dearmor > warpdotdev.gpg + sudo install -D -o root -g root -m 644 warpdotdev.gpg /etc/apt/keyrings/warpdotdev.gpg + sudo sh -c 'echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/warpdotdev.gpg] https://releases.warp.dev/linux/deb stable main" > /etc/apt/sources.list.d/warpdotdev.list' + rm warpdotdev.gpg + sudo apt update && sudo apt install warp-terminal + ``` + + See the instructions for other Linux distros on our [Quick Start Guide](/getting-started/quickstart/installation-and-setup/#linux). + </TabItem> +</Tabs> diff --git a/src/content/docs/support-and-community/troubleshooting-and-support/logging-out-and-uninstalling.mdx b/src/content/docs/support-and-community/troubleshooting-and-support/logging-out-and-uninstalling.mdx new file mode 100644 index 0000000..88d5054 --- /dev/null +++ b/src/content/docs/support-and-community/troubleshooting-and-support/logging-out-and-uninstalling.mdx @@ -0,0 +1,159 @@ +--- +title: "Logging out & uninstalling" +description: >- + How to log out from Warp, and how to uninstall Warp. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +## Logging out + +You can log out of Warp through: + +* **Settings** > **Account**, with the "Log out" button +* [Command Palette](/terminal/command-palette/), with the "Log out" item. + +<DemoVideo src="/assets/support-and-community/logout.mp4" label="Logout Demo" /> + +### Known issues: + +1. When you log out, you will lose all running processes and all unsaved objects. +2. When you log out and log in to Warp with another account, the following preferences will be preserved from the original account: + 1. Theme + 2. Keybindings + 3. Settings (e.g. autosuggestion, notifications, font size, welcome tips status) +3. Whenever you log in to Warp, you will receive the onboarding survey. + +## Uninstalling Warp + +Removing Warp from your computer involves uninstalling Warp and then removing any files or data. + +:::note +If you're using Warp Preview, replace "Warp-Stable" with "Warp-Preview" in the commands below (e.g., `defaults delete dev.warp.Warp-Preview`). +::: + +<Tabs> + <TabItem label="macOS"> + **Uninstalling Warp by dmg** + + * Remove Warp with `sudo rm -r /Applications/Warp.app` + * Open **Finder** > **Applications**, right-click on Warp, and select "Move to Trash" + + **Uninstalling Warp by Homebrew** + + * Remove Warp with `brew uninstall warp` + + **Removing Warp settings, files, logs, and database** + + ```bash + # Remove Warp settings defaults + defaults delete dev.warp.Warp-Stable + # Remove Warp logs + sudo rm -r $HOME/Library/Logs/warp.log + # Remove Warp database, Codebase Context, and MCP logs + sudo rm -r "$HOME/Library/Group Containers/2BBY89MBSN.dev.warp/Library/Application Support/dev.warp.Warp-Stable" + # Remove Warp user files, themes, and launch configurations + sudo rm -r $HOME/.warp + # Note: Removing $HOME/.warp will delete files for both Stable and Preview. + # If you wish to delete it all, then: sudo rm -r $HOME/.warp + ``` + + **For Warp Preview users:** + + ```bash + # Remove Warp Preview settings defaults + defaults delete dev.warp.Warp-Preview + # Remove Warp Preview logs + sudo rm -r $HOME/Library/Logs/warp_preview.log + # Remove Warp Preview database, Codebase Context, and MCP logs + sudo rm -r "$HOME/Library/Group Containers/2BBY89MBSN.dev.warp/Library/Application Support/dev.warp.Warp-Preview" + # Note: Removing $HOME/.warp will delete files for both Preview and Stable. + # If you wish to delete it all, then: sudo rm -r $HOME/.warp + ``` + </TabItem> + <TabItem label="Windows"> + **Uninstalling Warp by WinGet** + + ```powershell + winget uninstall Warp.Warp + ``` + + **Uninstalling Warp installed by Installer** + + * Search for "Installed apps" section of the Control Panel. + * Search for and Uninstall the Warp application + + **Removing Warp settings, files, logs, and database** + + ```powershell + # Remove Warp settings in the Windows Registry + Remove-Item -Path "HKCU:\Software\Warp.dev\Warp" -Recurse -Force + # Remove Warp user files, logs, database, Codebase Context, and MCP logs + Remove-Item -Path "$env:LOCALAPPDATA\warp\Warp" -Recurse -Force + # Remove Warp themes and launch configurations + Remove-Item -Path "$env:APPDATA\warp\Warp" -Recurse -Force + ``` + + **For Warp Preview users:** + + ```powershell + # Remove Warp Preview settings in the Windows Registry + Remove-Item -Path "HKCU:\Software\Warp.dev\Warp-Preview" -Recurse -Force + # Remove Warp Preview user files, logs, database, Codebase Context, and MCP logs + Remove-Item -Path "$env:LOCALAPPDATA\warp\Warp-Preview" -Recurse -Force + # Remove Warp Preview themes and launch configurations + Remove-Item -Path "$env:APPDATA\warp\Warp-Preview" -Recurse -Force + ``` + </TabItem> + <TabItem label="Linux"> + **Uninstalling Warp by package manager** + + ```bash + # apt uninstall + sudo apt remove warp-terminal + # dnf uninstall + sudo dnf remove warp-terminal + # zypper uninstall + sudo zypper remove warp-terminal + # pacman uninstall + sudo pacman -R warp-terminal + ``` + + * Uninstall Warp using the same package manager that you used to [install](/getting-started/quickstart/installation-and-setup/) it. + + **Removing Warp settings, files, logs, and database** + + ```bash + # Remove Warp settings files + rm -r ${XDG_CONFIG_HOME:-$HOME/.config}/warp-terminal + # Remove Warp user files, logs, database, Codebase Context, and MCP logs + rm -r ${XDG_STATE_HOME:-$HOME/.local/state}/warp-terminal + # Remove Warp themes and launch configurations + rm -r ${XDG_STATE_HOME:-$HOME/.local/share}/warp-terminal + ``` + + **For Warp Preview users:** + + ```bash + # apt uninstall + sudo apt remove warp-terminal-preview + # dnf uninstall + sudo dnf remove warp-terminal-preview + # zypper uninstall + sudo zypper remove warp-terminal-preview + # pacman uninstall + sudo pacman -R warp-terminal-preview + ``` + + * Uninstall Warp Preview using the same package manager that you used to install it. + + ```bash + # Remove Warp Preview settings files + rm -r ${XDG_CONFIG_HOME:-$HOME/.config}/warp-terminal-preview + # Remove Warp Preview user files, logs, database, Codebase Context, and MCP logs + rm -r ${XDG_STATE_HOME:-$HOME/.local/state}/warp-terminal-preview + # Remove Warp Preview themes and launch configurations + rm -r ${XDG_STATE_HOME:-$HOME/.local/share}/warp-terminal-preview + ``` + </TabItem> +</Tabs> diff --git a/src/content/docs/support-and-community/troubleshooting-and-support/sending-us-feedback.mdx b/src/content/docs/support-and-community/troubleshooting-and-support/sending-us-feedback.mdx new file mode 100644 index 0000000..3b30f53 --- /dev/null +++ b/src/content/docs/support-and-community/troubleshooting-and-support/sending-us-feedback.mdx @@ -0,0 +1,293 @@ +--- +title: Sending feedback and logs +description: >- + Send Warp feedback, bug reports, and feature requests, and gather logs, + crash reports, CPU samples, and AI debugging IDs to attach to them. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +### Sending Warp feedback + +* Use the [`/feedback`](#using-feedback-in-warp) slash command inside Warp to draft and file a GitHub issue without leaving the terminal. +* Open a new bug or feature request in our [GitHub repository](https://github.com/warpdotdev/warp/issues/new/choose). +* Join our [Warp Community Slack](https://go.warp.dev/join-preview) and share feedback in **#feedback-general**, or **#feedback-preview** if it is specific to [Warp Preview](/support-and-community/community/warp-preview-and-alpha-program/). +* For security issues or questions, email [security@warp.dev](mailto:security@warp.dev). +* For questions about privacy, email [privacy@warp.dev](mailto:privacy@warp.dev). + +#### Subscriber and Enterprise + +* For subscriber technical issues or questions (bugs, credits, etc.), email [support@warp.dev](mailto:support@warp.dev). +* For subscriber billing issues or questions (refunds, cancellation, etc.), email [billing@warp.dev](mailto:billing@warp.dev). +* For enterprise, please direct all feedback and issues to your designated Slack channel. + +<DemoVideo src="/assets/support-and-community/send-feedback-demo.mp4" label="sending feedback from the macOS menu and Warp Essentials" /> + +## Using `/feedback` in Warp + +The `/feedback` [slash command](/agent-platform/capabilities/slash-commands/) is the fastest way to report a Warp bug, flag a regression, or file a feature request from inside the terminal. It files issues against [`warpdotdev/warp`](https://github.com/warpdotdev/warp) so the Warp team can triage reports quickly. + +`/feedback` has two flows, and Warp picks the right one automatically based on whether AI is enabled for your account: + +* **AI enabled** — the Agent drafts and files the issue for you. +* **AI disabled** — Warp opens the GitHub new-issue picker in your browser so you can write and submit the report yourself. + +### With AI enabled + +When AI is enabled, `/feedback` hands your report to the Agent, which polishes and files your issue in a single turn. The Agent: + +1. **Classifies** your report by type (bug, regression, UX issue, or feature request). +2. **Asks clarifying questions** only when the report is too vague to draft responsibly. For example, when expected behavior, reproduction steps, or the affected platform aren't clear. +3. **Checks for duplicates** in `warpdotdev/warp` and, if a likely duplicate exists, links you to that issue instead of filing a new one. +4. **Files the issue** in `warpdotdev/warp`, either directly or by opening a prefilled new-issue page in your browser. + +:::note +This flow uses the Agent to draft your issue, so it consumes [credits](/support-and-community/plans-and-billing/credits/) like any other Agent conversation. +::: + +#### Attaching screenshots + +You can attach screenshots to your `/feedback` request the same way you attach images to any other Agent prompt (drag-and-drop into the input, paste from the clipboard, or use the attach button). When one or more images are attached, the Agent: + +* Includes a short caption for each screenshot in the drafted issue body, so the report stays coherent even if an image never makes it to the final GitHub issue. +* Opens the prefilled new-issue page in your browser with placeholder lines (for example, `_Paste screenshot 1 here_`) indicating exactly where to drop each image. Screenshots have to be added in the browser because GitHub doesn't yet support attaching images to issues over its API. +* Reminds you in its final reply that the issue is drafted but not filed. To complete filing, drop your screenshots into the placeholder lines and click **Submit new issue**. + +### With AI disabled + +When AI is disabled for your account, `/feedback` (and the **Feedback** button in Warp Essentials) skips the Agent and opens the GitHub new-issue picker for `warpdotdev/warp` directly in your browser, with your current Warp version and operating system prefilled as query parameters. No Agent is invoked and no credits are consumed. You write and submit the issue yourself through GitHub's web UI. + +If you're unsure whether AI is enabled for your account, open the Warp app and go to **Settings** > **Agents** > **Warp Agent**. + +### What to include + +Whether you use the `/feedback` slash command or file an issue manually, a good feedback report answers these questions up front: + +* **What happened?** Describe the observed behavior in one or two sentences. +* **What did you expect?** Describe the behavior you expected instead. +* **How do we reproduce it?** List numbered steps when possible. If you can't reproduce the issue reliably, mention that too. +* **What version of Warp are you on?** `/feedback` fills this in automatically; for manual reports, copy it from **Settings** > **Account**. +* **Logs, screenshots, or debugging IDs.** See [Gathering Warp Logs](#gathering-warp-logs), [Collecting crash reports on macOS](#collecting-crash-reports-on-macos), or [Gathering AI debugging ID](#gathering-ai-debugging-id) below. + +See the [Slash Commands reference](/agent-platform/capabilities/slash-commands/) for the full list of commands available in Warp. + +## Gathering Warp Logs + +Retrieve Warp's logs by following the instructions for your platform below. Locate the log file and attach it to your GitHub issue or email. + +:::note +Warp's logs and crash reports _**do not**_ contain any console input or output. See more on how we handle [Crash Reports and Telemetry](/support-and-community/privacy-and-security/privacy/#what-telemetry-data-are-you-collecting-and-why). +::: + +<Tabs> + <TabItem label="macOS"> + The Warp log files are located at `~/Library/Logs/`. + + **Warp logs on macOS** + + Run the following to zip the Warp logs to your Desktop: + + ```bash + zip -j ~/Desktop/warp-logs.zip ~/Library/Logs/warp.log* + ``` + + **Warp Preview logs on macOS** + + Run the following to zip the Warp Preview logs to your Desktop: + + ```bash + zip -j ~/Desktop/warp_preview-logs.zip ~/Library/Logs/warp_preview.log* + ``` + + :::caution + If your issue is graphical (e.g. no display of windows) or a crash, please run Warp with the following command to capture more log information: + + ```bash + # Run if Warp on macOS is installed + RUST_LOG=wgpu_core=info,wgpu_hal=info /Applications/Warp.app/Contents/MacOS/stable + + # Run if Warp Preview on macOS is installed + RUST_LOG=wgpu_core=info,wgpu_hal=info /Applications/WarpPreview.app/Contents/MacOS/preview + ``` + ::: + </TabItem> + <TabItem label="Windows"> + The Warp log files are located at `$env:LOCALAPPDATA\warp\Warp\data\logs\`. + + **Warp logs on Windows** + + Close Warp and run the following from another terminal to zip the logs to your Desktop: + + ```powershell + Compress-Archive -Path "$env:LOCALAPPDATA\warp\Warp\data\logs\warp.log*" -DestinationPath "$([Environment]::GetFolderPath('Desktop'))\warp-logs.zip" + ``` + + **Warp Preview logs on Windows** + + Close Warp Preview and run the following from another terminal to zip the logs to your Desktop: + + ```powershell + Compress-Archive -Path "$env:LOCALAPPDATA\warp\WarpPreview\data\logs\warp_preview.log*" -DestinationPath "$([Environment]::GetFolderPath('Desktop'))\warp_preview-logs.zip" + ``` + + :::caution + If your issue is graphical (e.g. no display of windows) or a crash, please run Warp with the following command to capture more log information: + + ```powershell + # Run if Warp on Windows is installed for a single user + $env:RUST_LOG="wgpu_core=info,wgpu_hal=info"; & "$env:LOCALAPPDATA\Programs\Warp\warp.exe" + + # Run if Warp on Windows is installed for all users + $env:RUST_LOG="wgpu_core=info,wgpu_hal=info"; & "$env:PROGRAMFILES\Warp\warp.exe" + + # Run if Warp Preview on Windows is installed for a single user + $env:RUST_LOG="wgpu_core=info,wgpu_hal=info"; & "$env:LOCALAPPDATA\Programs\WarpPreview\preview.exe" + + # Run if Warp Preview on Windows is installed for all users + $env:RUST_LOG="wgpu_core=info,wgpu_hal=info"; & "$env:PROGRAMFILES\WarpPreview\preview.exe" + ``` + ::: + </TabItem> + <TabItem label="Linux"> + The Warp log files are located at `~/.local/state/warp-terminal/`. + + **Warp logs on Linux** + + Run the following to zip the Warp logs to your home directory: + + ```bash + tar -czf ~/warp-logs.tar.gz -C ~/.local/state/warp-terminal warp.log* + ``` + + **Warp Preview logs on Linux** + + Run the following to zip the Warp Preview logs to your home directory: + + ```bash + tar -czf ~/warp_preview-logs.tar.gz -C ~/.local/state/warp-terminal-preview warp_preview.log* + ``` + + :::caution + If your issue is graphical (e.g. no display of windows) or a crash, please run Warp with the following command to capture more log information: + + ```bash +# Run if Warp on Linux is installed + RUST_LOG=wgpu_core=info,wgpu_hal=info MESA_DEBUG=1 EGL_LOG_LEVEL=debug warp-terminal + + # Run if Warp Preview on Linux is installed + RUST_LOG=wgpu_core=info,wgpu_hal=info MESA_DEBUG=1 EGL_LOG_LEVEL=debug warp-terminal-preview +``` + ::: + </TabItem> +</Tabs> + +## Collecting crash reports on macOS + +If Warp crashes, macOS may generate `.ips` crash report files in `~/Library/Logs/DiagnosticReports/`. Run the following to collect all Warp crash reports into a zip on your Desktop: + +```bash +files=$(find ~/Library/Logs/DiagnosticReports -name "*.ips" -exec grep -l "dev\.warp" {} + 2>/dev/null) && [ -n "$files" ] && echo "$files" | xargs zip -j ~/Desktop/warp-crash-logs.zip || echo "No Warp crash reports found." +``` + +Attach the resulting `warp-crash-logs.zip` to your [bug report](/support-and-community/troubleshooting-and-support/sending-us-feedback/#sending-warp-feedback). + +:::note +This command searches crash report files for Warp's bundle identifier, so it works across all Warp channels (Stable, Preview). +::: + +## Collecting debug info on Windows + +Occasionally, the Warp team may ask you to provide debugging information on Windows OS in particular with one of the following: + +```powershell +# If Warp is in your PATH, Run: +warp --dump-debug-info + +# Otherwise you may need to use an absolute path and ... +# Warp on Windows is installed for a single user, Run: +& $env:LOCALAPPDATA\programs\Warp\warp.exe --dump-debug-info + +# Warp on Windows is installed for all users, Run: +& $env:PROGRAMFILES\Warp\warp.exe --dump-debug-info +``` + +## Collecting CPU samples + +Certain conditions can cause Warp to use more CPU than expected or become unresponsive. Collecting a CPU sample while the issue is happening is the best way to report it. The sample provides the information the Warp team needs to identify and fix the root cause. + +Collect a sample using the steps for your platform and attach it to a new [GitHub issue](https://github.com/warpdotdev/warp/issues/new/choose). + +<Tabs> + <TabItem label="macOS"> + 1. Reproduce the high CPU usage or unresponsiveness in Warp. + 2. While the issue is occurring, open **Activity Monitor**, select the **Warp** process, and click **Sample Process**. + + ![Sampling the Warp process in Activity Monitor](../../../../assets/support-and-community/activity-monitor-sample-process.png) + + 3. Save the resulting sample and attach it to your GitHub issue. + </TabItem> + <TabItem label="Windows"> + Install [`samply`](https://github.com/mstange/samply) to record a CPU trace: + + ```powershell + powershell -ExecutionPolicy Bypass -c "irm https://github.com/mstange/samply/releases/download/samply-v0.13.1/samply-installer.ps1 | iex" + ``` + + 1. Find the Warp process ID: + + ```powershell + Get-Process *warp* + ``` + + 2. Start recording, replacing `<PID>` with the process ID from the previous step: + + ```powershell + samply record -p <PID> + ``` + + 3. Reproduce the issue that causes high CPU usage or unresponsiveness. + 4. Press `Ctrl+C` to stop recording. `samply` opens the profile in the Firefox Profiler in your browser. Click the upload icon in the top-right corner to generate a shareable link, then paste it into your GitHub issue. + </TabItem> + <TabItem label="Linux"> + Install [`samply`](https://github.com/mstange/samply) to record a CPU trace: + + ```bash + curl --proto '=https' --tlsv1.2 -LsSf https://github.com/mstange/samply/releases/download/samply-v0.13.1/samply-installer.sh | sh + ``` + + :::caution + `samply` requires access to Linux perf events. If you get a permission error, run: + + ```bash + echo '-1' | sudo tee /proc/sys/kernel/perf_event_paranoid + ``` + ::: + + 1. Start recording the Warp process: + + ```bash + samply record -p $(pgrep -f warp-terminal) + ``` + + 2. Reproduce the issue that causes high CPU usage or unresponsiveness. + 3. Press `Ctrl+C` to stop recording. `samply` opens the profile in the Firefox Profiler in your browser. Click the upload icon in the top-right corner to generate a shareable link, then paste it into your GitHub issue. + + :::note + If you prefer not to install `samply`, you can use the built-in `perf` tool instead: + + ```bash + perf record -g -p $(pgrep -f warp-terminal) -- sleep 30 + ``` + + Attach the resulting `perf.data` file from your current directory to your GitHub issue. + ::: + </TabItem> +</Tabs> + +## Gathering AI debugging ID + +To gather the debugging ID, `RIGHT-CLICK` on the AI conversation block in question and select "Copy debugging ID", then paste that into the [bug report](/support-and-community/troubleshooting-and-support/sending-us-feedback/#sending-warp-feedback) that you submit so that our team can investigate the issue. + +Whenever there is an error in the Agent Conversation, there will also be an option to directly copy the debugging ID for the bug report. + +![Agent Mode error message with Send Feedback button and debug information containing request and conversation IDs](../../../../assets/support-and-community/send-feedback-debugging-information.png) diff --git a/src/content/docs/support-and-community/troubleshooting-and-support/troubleshooting-login-issues.mdx b/src/content/docs/support-and-community/troubleshooting-and-support/troubleshooting-login-issues.mdx new file mode 100644 index 0000000..e5627e3 --- /dev/null +++ b/src/content/docs/support-and-community/troubleshooting-and-support/troubleshooting-login-issues.mdx @@ -0,0 +1,108 @@ +--- +title: Troubleshooting Login +description: >- + Fix common login issues including SSO, proxies, ad blockers, and auth + tokens. +--- +import DemoVideo from '@components/DemoVideo.astro'; + +## Can't sign up for or log into Warp + +Clicking it should open a signup or login pop-up. If clicking the button opens a blank pop-up window, try using a proxy. Your ISP or Firewall may be blocking the app's call to `*.googleapis.com`. + +:::note +In some older Ruby development environments, `.dev` domains do not resolve properly and you may need to delete the `/etc/resolver/dev`, see more [here](https://superuser.com/questions/1374892/dev-domains-dont-resolve). +::: + +## All browsers + +This error could occur if you installed an ad blocker or have stale browser cookies, including our Firebase auth pop-up. **To fix it:** + +1. Disable your ad blocker for `app.warp.dev` +2. Clear any cookies and cache, or open an incognito / private browser window +3. Try [http://app.warp.dev/login](http://app.warp.dev/login) again + +### Safari + +If you are using Safari, you may see the following messages in your console: + +1. `Unable to access localStorage` +2. And every time you click the "Sign Up" button, you get `Unhandled Promise Rejection: Error: This operation is not supported in the environment the application is running on. "location.protocol" must be http, https, or chrome-extension and web storage must be enabled.` + +This error likely occurs because you are blocking all cookies in Safari's security settings, but Firebase Auth requires the cookie to record whether the user is logged in. **To fix it:** + +1. Go to Safari Preferences > Privacy +2. Uncheck the "Block all cookies" checkbox + +## Proxies + +When behind a proxy, a possible workaround is to disable QUIC in the browser. It will then fall back to TCP and likely allow login. + +* In Chrome, or Chromium-based browsers like Edge, Opera, and Arc, type `chrome://flags` into the address bar. + 1. In the search bar on the flags page, type `Experimental QUIC protocol`. + 2. Locate the "Experimental QUIC protocol" flag and click on the drop-down menu next to it. + 3. Select "Disabled" from the options. + 4. Relaunch Chrome for the changes to take effect. +* In Firefox, type `about:config` into the address bar. + 1. You will see a warning message. Click on the "Accept the Risk and Continue" button. + 2. In the search bar, type `network.http.http3.enable`. + 3. Double-click on the `network.http.http3.enable` preference to set its value to `false`. This will disable QUIC in Firefox. + 4. Restart Firefox for the changes to take effect. +* In Safari, unfortunately, there is no built-in option to disable QUIC in Safari. Safari uses QUIC as its default transport protocol and does not provide a user-accessible setting to disable it. + +## SSO login + +### Can't open Warp from SSO + +When directly launching Warp from Okta or other SSO providers', you may see an error message like "`Unable to process request due to missing initial state...`". This is due to a limitation with Warp authentication APIs. Instead, do the following: + +1. Go to [app.warp.dev/login](http://app.warp.dev/login) +2. Choose “Continue with SSO” +3. Login with your normal SSO credentials + +### I logged in with another method before and now can't use SSO + +In cases where you logged in with another method, please do the following to fix SSO login: + +1. Go to [app.warp.dev/login](http://app.warp.dev/login) +2. Login with the original method that you used to create your Warp account (email, Google, GitHub). +3. Once logged in, go to [app.warp.dev/link\_sso](https://app.warp.dev/link_sso) +4. This should link your login to SSO. You can now proceed to login with "Continue with SSO". + +## Flagged as fraudulent + +If you received the message "This account has been flagged as fraudulent.", this means that you have failed one or more checks in our fraud detection system, and you will be unable to authenticate to Warp or leverage AI features. + +Please note that creating multiple accounts or using throwaway emails is against our [Terms of Service](https://www.warp.dev/terms-of-service) and increases the chance of triggering this system significantly. + +### False positives + +At times, ad-blockers or systems like Pi-hole may falsely trigger this system. You may be able to remediate this error by temporarily disabling these and attempting login again. + +### Requesting an appeal + +If you are still unable to authenticate, you may email [appeals@warp.dev](mailto:appeals@warp.dev) to request an appeal. Please include the email of the account you are experiencing the issue on so a member of our support team can investigate. This may take 5-10 days. + +If you have an active subscription and continue to have login issues, please see the rest of the recommendations on [this page](/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/#get-help-with-login-issues). + +## How to get an Auth token to login + +If the browser does not open from Warp directly when you click "Sign up" or "Sign in". Please go to the [Signup](https://app.warp.dev/signup) page to create an account or [Login](https://app.warp.dev/login) page if you already have one, then copy the auth token from the "here" link on the logged\_in page and paste it into Warp. + +If nothing happens when you click "Take me to Warp" on the logged-in page. If this happens to you, copy the "here" link on the web logged-in page (https://app.warp.dev/logged\_in) to copy the authentication token, then paste it into the app as shown below. + +:::caution +On Linux and Windows, the default copy-and-paste [Keyboard shortcuts](/getting-started/keyboard-shortcuts/) are `CTRL+SHIFT+C` and `CTRL+SHIFT+V` respectively.\ +\ +On Linux and WSL you should install and set your default `$BROWSER` to `brave-browser` to workaround any copy-paste issues. Please see the workaround guide below. +::: + +<DemoVideo src="/assets/support-and-community/auth-token-demo.mp4" label="Authentication Token Linux" /> + +![Authentication Token macOS](../../../../assets/support-and-community/auth-token-flow.png) + +If "Take me to Warp" is still not working it may be due to a [proxy issue](/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/#proxies), please see this article for more information on a workaround [here](https://embiid.blog/post/WARP-does-not-work-after-submitting-an-invite-code/). + +## Get help with login issues + +If Sign Up or Login does not work after trying the steps above, please [contact us](https://www.warp.dev/contact) for support. diff --git a/src/content/docs/support-and-community/troubleshooting-and-support/updating-warp.mdx b/src/content/docs/support-and-community/troubleshooting-and-support/updating-warp.mdx new file mode 100644 index 0000000..7f4102c --- /dev/null +++ b/src/content/docs/support-and-community/troubleshooting-and-support/updating-warp.mdx @@ -0,0 +1,100 @@ +--- +title: Updating Warp +description: >- + Check for updates, troubleshoot auto-update permissions, and refresh signing + keys. +--- +import DemoVideo from '@components/DemoVideo.astro'; + +Warp automatically checks for updates on startup. A notification will appear in the top right corner of the Warp window when a new update is available. + +![Update Available](../../../../assets/support-and-community/update-available.png) + +To check for updates, search for "update" in the [Command Palette](/terminal/command-palette/) or go to **Settings** > **Account** and click "Check for Update". + +<DemoVideo src="/assets/support-and-community/check-for-update.mp4" label="Check for Update manually" /> + +If nothing happens, it means you already have the latest stable build. + +## macOS: Auto-update permissions issues + +Warp cannot auto-update if it does not have the correct permissions to replace the running version of Warp. If this is the case, a banner will prompt you to manually update Warp. + +![Update Available](../../../../assets/support-and-community/update-available-bar.png) + +There are 2 main causes of this: + +1. You opened Warp directly from the mounted volume instead of dragging it into your Applications directory. If this is the case, the easiest fix is to quit Warp, drag the application into /Applications, and restart Warp. +2. You are a non-Admin user. This can happen if you use a computer with multiple profiles. If you have admin access on the computer, opening the app with the admin user should fix the auto-update issues. + +:::note +(Oct 2022): There is a known issue with [auto-update on macOS Ventura](/support-and-community/troubleshooting-and-support/known-issues/#auto-update-on-macos-ventura). +::: + +## Linux: Refreshing the package signing key + +If you encounter signature verification errors when trying to update Warp on Linux, you may need to refresh the package signing key. This can happen if the key on your system has expired. + +### Debian / Ubuntu (apt) + +You may see an error like the following: + +``` +W: GPG error: https://releases.warp.dev/linux/deb stable Release: The following signatures were invalid: EXPKEYSIG 31F4254AFE49E02E Warp Linux Maintainers (Package Signing Authority) <linux-maintainers@warp.dev> +E: The repository 'https://releases.warp.dev/linux/deb stable Release' is not signed. +``` + +To fetch the updated signing key, run: + +```bash +curl -fsSL https://releases.warp.dev/linux/keys/warp.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/warpdotdev.gpg > /dev/null +``` + +Then retry your update: + +```bash +sudo apt update && sudo apt install warp-terminal +``` + +### Fedora / RHEL / CentOS (dnf/yum) + +You may see an error like the following: + +``` +OpenPGP check for package "warp-terminal-v0.2026.01.28.08.14.stable_04-1.x86_64" (/var/cache/libdnf5/warpdotdev-4ac10ef632833104/packages/warp-terminal-v0.2026.01.28.08.14.stable_04-1.x86_64.rpm) from repo "warpdotdev" has failed: Problem occurred when opening the package. +``` + +To fetch the updated signing key, run: + +```bash +sudo rpm --import https://releases.warp.dev/linux/keys/warp.asc +``` + +Then retry your update: + +```bash +sudo dnf upgrade warp-terminal +# or for older systems: +sudo yum upgrade warp-terminal +``` + +### Arch Linux (pacman) + +You may see an error like the following: + +``` +error: warpdotdev: signature from "Warp Linux Maintainers (Package Signing Authority) <linux-maintainers@warp.dev>" is expired +``` + +To fetch the updated signing key, run: + +```bash +sudo pacman-key --recv-keys "linux-maintainers@warp.dev" --keyserver hkp://keys.openpgp.org:80 +sudo pacman-key --lsign-key "linux-maintainers@warp.dev" +``` + +Then retry your update: + +```bash +sudo pacman -Syu warp-terminal +``` diff --git a/src/content/docs/support-and-community/troubleshooting-and-support/using-warp-offline.mdx b/src/content/docs/support-and-community/troubleshooting-and-support/using-warp-offline.mdx new file mode 100644 index 0000000..3a071c2 --- /dev/null +++ b/src/content/docs/support-and-community/troubleshooting-and-support/using-warp-offline.mdx @@ -0,0 +1,32 @@ +--- +title: Using Warp Offline +description: >- + Using Warp offline and what features are supported. +--- + +The first time you download and open Warp, you will need to be online for the initial setup. After the initial setup Warp’s core terminal features will work as expected when you’re offline, regardless of whether you are logged in or logged out. + +Requiring all users, logging in or logged out, to be online when first accessing Warp is required to allow use of Warp's AI and cloud features. When you first open the app, we create a unique user-ID to meter AI-usage and attach cloud objects to specific accounts. If you opt to use Warp logged-out, this unique ID is attached to an anonymous user account. + +:::note +Warp is "Offline" when you aren't connected to the internet, or if you're blocking calls `app.warp.dev` on your network. There is no explicit Offline Mode in Warp. +::: + +### Cloud-based features require online access + +Warp’s cloud-based features which require an internet connection will not work in offline mode. Those features include: + +* [Warp Drive](/knowledge-and-collaboration/warp-drive/#using-warp-drive-offline) (Some files may be read-only in offline mode) +* [Oz agent](/agent-platform/local-agents/overview/) + * [Agent Mode](/agent-platform/local-agents/interacting-with-agents/) + * [Generate](/agent-platform/local-agents/overview/) + * [AI Autofill](/knowledge-and-collaboration/warp-drive/workflows/#warp-ai-autofill) + * [Prompts](/knowledge-and-collaboration/warp-drive/prompts/) + * [Active AI Recommendations](/agent-platform/local-agents/active-ai/) + * [Voice](/agent-platform/local-agents/interacting-with-agents/voice/) + * [Rules](/agent-platform/capabilities/rules/) + * [Model Context Protocol](/agent-platform/capabilities/mcp/) +* [Teams](/knowledge-and-collaboration/teams/) +* [Session Sharing](/knowledge-and-collaboration/session-sharing/) +* [Block Sharing](/terminal/blocks/block-sharing/) +* [Refer a Friend](/support-and-community/community/refer-a-friend/) diff --git a/src/content/docs/terminal/appearance/app-icons.mdx b/src/content/docs/terminal/appearance/app-icons.mdx new file mode 100644 index 0000000..6c6b045 --- /dev/null +++ b/src/content/docs/terminal/appearance/app-icons.mdx @@ -0,0 +1,59 @@ +--- +title: Custom app icons +description: >- + Choose from a palette of built-in app icons to customize Warp's dock + appearance on macOS. +--- +import ImageGrid from '@components/ImageGrid.astro'; +import ImageGridItem from '@components/ImageGridItem.astro'; +import iconDefault from '../../../../assets/terminal/moody-dev-default-icon.png'; +import iconWarp1 from '../../../../assets/terminal/default-icon.png'; +import iconAurora from '../../../../assets/terminal/aurora-icon.png'; +import iconClassic1 from '../../../../assets/terminal/classic1-icon.png'; +import iconClassic2 from '../../../../assets/terminal/classic2-icon.png'; +import iconClassic3 from '../../../../assets/terminal/classic3-icon.png'; +import iconComets from '../../../../assets/terminal/comets-icon.png'; +import iconGlassSky from '../../../../assets/terminal/glass-sky-icon.png'; +import iconGlitch from '../../../../assets/terminal/glitch-icon.png'; +import iconGlow from '../../../../assets/terminal/glow-icon.png'; +import iconHolographic from '../../../../assets/terminal/holographic-icon.png'; +import iconMono from '../../../../assets/terminal/mono-icon.png'; +import iconNeon from '../../../../assets/terminal/neon-icon.png'; +import iconOriginal from '../../../../assets/terminal/original-icon.png'; +import iconStarburst from '../../../../assets/terminal/starburst-icon.png'; +import iconSticker from '../../../../assets/terminal/sticker-icon.png'; + +:::note +App icons are only available for Warp on macOS. The feature doesn't support custom dock icons. +::: + +## How to change the app icon + +* Navigate to **Settings** > **Appearance** > **Icon** > **Customize your app icon** +* Select the desired dock icon from the drop down menu + +![Icon customization drop-down menu](../../../../assets/terminal/custom-dock-icon-dropdown.png) + +## Dock icons + +By default, Warp ships with these dock icons: + +<ImageGrid> + <ImageGridItem src={iconDefault} label="Default" /> + <ImageGridItem src={iconWarp1} label="Warp 1.0" /> + <ImageGridItem src={iconAurora} label="Aurora" /> + <ImageGridItem src={iconClassic1} label="Classic 1" /> + <ImageGridItem src={iconClassic2} label="Classic 2" /> + <ImageGridItem src={iconClassic3} label="Classic 3" /> + <ImageGridItem src={iconComets} label="Comets" /> + <ImageGridItem src={iconGlassSky} label="Glass Sky" /> + <ImageGridItem src={iconGlitch} label="Glitch" /> + <ImageGridItem src={iconGlow} label="Glow" /> + <ImageGridItem src={iconHolographic} label="Holographic" /> + <ImageGridItem src={iconMono} label="Mono" /> + <ImageGridItem src={iconNeon} label="Neon" /> + <ImageGridItem src={iconOriginal} label="Original" /> + <ImageGridItem src={iconStarburst} label="Starburst" /> + <ImageGridItem src={iconSticker} label="Sticker" /> +</ImageGrid> + diff --git a/src/content/docs/terminal/appearance/blocks-behavior.mdx b/src/content/docs/terminal/appearance/blocks-behavior.mdx new file mode 100644 index 0000000..4e4de95 --- /dev/null +++ b/src/content/docs/terminal/appearance/blocks-behavior.mdx @@ -0,0 +1,37 @@ +--- +title: Blocks Behavior +description: >- + Customize Block spacing with Compact mode and toggle Block dividers for a + cleaner layout. +--- +import DemoVideo from '@components/DemoVideo.astro'; + +## Compact Mode + +Warp offers the option to enable Compact mode, which condenses the spacing between [Blocks](/terminal/blocks/), enabling more content to be in view. + +### How to enable Compact Mode + +Compact mode is disabled by default, but can be toggled in the following ways: + +* Navigate to **Settings** > **Appearance** > **Blocks** > **Compact Mode**. +* Utilize the [Command Palette](/terminal/command-palette/), then search for "Compact mode" to toggle. + +:::note +Warp will open with the same compact settings in future sessions. +::: + +<DemoVideo src="/assets/terminal/compact_mode.mp4" label="Compact Mode Demo" /> + +## Block Dividers + +Warp [Blocks](/terminal/blocks/) are divided by horizontal lines that separate individual command input and output, they create a visual break between different commands that you run in a session. + +### How to toggle block dividers + +Block dividers are enabled by default, but can be toggled in the following ways: + +* Navigate to **Settings** > **Appearance** > **Blocks** > **Show block dividers**. +* Utilize the [Command Palette](/terminal/command-palette/), then search for "Block Dividers". + +<DemoVideo src="/assets/terminal/block-divider-demo.mp4" label="Block Divider Demo" /> diff --git a/src/content/docs/terminal/appearance/custom-themes.mdx b/src/content/docs/terminal/appearance/custom-themes.mdx new file mode 100644 index 0000000..5da9431 --- /dev/null +++ b/src/content/docs/terminal/appearance/custom-themes.mdx @@ -0,0 +1,268 @@ +--- +title: Custom Themes +description: >- + Warp supports Custom Themes which can be created manually or downloaded from + our repo. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +:::note +Examples and a collection of themes can be found in the [Warp themes repository](https://github.com/warpdotdev/themes). +::: + +## Warp's custom theme repository + +We have a [repository of themes hosted on GitHub.](https://github.com/warpdotdev/themes) + +Each theme has a preview generated in the README. + +The main difference between "standard" and "base16" themes is that "standard" themes follow the typical color setup, while "base16" themes follow the framework suggested by [@chriskempson](https://github.com/chriskempson/base16). + +There are 2 ways to install a theme from this repo. + +1. Download a single file and follow the steps in the section below. +2. Clone the entire repo into the appropriate location based on your OS below: + +<Tabs> + <TabItem label="macOS"> + ```bash + mkdir -p $HOME/.warp + cd $HOME/.warp/ + git clone https://github.com/warpdotdev/themes.git + ``` + </TabItem> + <TabItem label="Windows"> + ```powershell + New-Item -Path "$env:APPDATA\warp\Warp\data\" -ItemType Directory + Set-Location -Path $env:APPDATA\warp\Warp\data\ + git clone https://github.com/warpdotdev/themes.git + ``` + </TabItem> + <TabItem label="Linux"> + ```bash + mkdir -p ${XDG_DATA_HOME:-$HOME/.local/share}/warp-terminal + cd ${XDG_DATA_HOME:-$HOME/.local/share}/warp-terminal/ + git clone https://github.com/warpdotdev/themes.git + ``` + </TabItem> +</Tabs> + +Here is a step-by-step YouTube video that goes through these 2 steps for an example theme. Note the location for the files is based on macOS. + +<VideoEmbed url="https://www.youtube.com/watch?v=UTYgwD-cLbk" title="Adding a Custom Theme to Warp" /> + +## How do I use a custom theme in Warp? + +1. To start, create the following directory: + +<Tabs> + <TabItem label="macOS"> + ```bash + mkdir -p $HOME/.warp/themes/ + ``` + </TabItem> + <TabItem label="Windows"> + ```powershell + New-Item -Path "$env:APPDATA\warp\Warp\data\themes\" -ItemType Directory + ``` + </TabItem> + <TabItem label="Linux"> + ```bash + mkdir -p ${XDG_DATA_HOME:-$HOME/.local/share}/warp-terminal/themes/ + ``` + </TabItem> +</Tabs> + +:::note +It may take several minutes for Warp to initially discover the new themes directory. You can either wait or restart Warp. After that step, all future changes to the directory will be reflected within seconds. +::: + +2. Add your new custom theme yaml file to this directory: + +```bash +cp ~/Downloads/my_awesome_theme.yaml {{path_to_your_themes_directory_from_step1}} +``` + +Your new theme should now be visible on the list of available themes. + +## Create your custom theme, manually + +Warp supports creating custom themes using .yaml files. + +The format is subject to change, but we do our best to avoid breaking changes and maintain forward compatibility. We also plan to support sharing and creating custom themes directly within Warp. + +A custom theme in Warp has the following `.yaml` structure: + +```yaml +name: Custom Theme # Name for the theme +accent: '#268bd2' # Accent color for UI elements +cursor: '#95D886' # Input cursor color (optional; defaults to accent color if omitted) +background: '#002b36' # Terminal background color +foreground: '#839496' # The foreground color +details: darker # Whether the theme is lighter or darker +terminal_colors: # Ansi escape colors + bright: + black: '#002b36' + blue: '#839496' + cyan: '#93a1a1' + green: '#586e75' + magenta: '#6c71c4' + red: '#cb4b16' + white: '#fdf6e3' + yellow: '#657b83' + normal: + black: '#073642' + blue: '#268bd2' + cyan: '#2aa198' + green: '#859900' + magenta: '#d33682' + red: '#dc322f' + white: '#eee8d5' + yellow: '#b58900' +``` + +:::note +Each color is represented in hex and must start with `#`. +::: + +* `name`: Name for the theme, will show up in the Theme picker. +* `accent`: Color used for highlights in Warp's UI +* `cursor`: Color for the input cursor (optional; defaults to accent color if omitted) +* `background`: Color of background +* `foreground`: Color of foreground +* `details`: Color used for detailing options + * `darker`: Color used for dark theme + * `lighter`: Color used for light-mode theme +* `terminal_colors`: Collection of normal & bright colors (16 total) known for other terminal themes (ANSI colors) + +## Create your custom theme, automatically + +Automatically create new themes based on a background image. Click the **+** button in the theme picker **Settings** > **Appearance** > **Themes** or search `Open Theme Picker` within the [Command Palette](/terminal/command-palette/). + +## Browse themes and use the theme creator + +Browse Warp's [theme repository](https://github.com/warpdotdev/themes) for ready-made themes, or use the in-app theme creator to generate the appropriate RGB values for your custom theme. Once the YAML file is created, you can edit the file to add the background images or gradients. + +## Background images and gradients + +To add a background image you can use this attribute: `background_image:` with the name of the image you want to use as the background. + +:::note +Note: Warp currently only supports images with the _.jpg_ file format: + +* `.jpeg` +* `.jpg` +* `.JPEG` +::: + +A `.yaml` config looks like this: + +```yaml +name: Custom Theme +accent: '#268bd2' +cursor: '#95D886' +background: '#002b36' +details: darker +foreground: '#839496' + +############################################################### SEE BELOW +background_image: + # the path is relative to ~/.warp/themes/ + # the full path to the picture is: ~/.warp/themes/warp.jpg + path: warp.jpg + # the opacity value is required and can range from 0-100 + opacity: 60 +############################################################### SEE ABOVE + +terminal_colors: + bright: + black: '#002b36' + blue: '#839496' + cyan: '#93a1a1' + green: '#586e75' + magenta: '#6c71c4' + red: '#cb4b16' + white: '#fdf6e3' + yellow: '#657b83' + normal: + black: '#073642' + blue: '#268bd2' + cyan: '#2aa198' + green: '#859900' + magenta: '#d33682' + red: '#dc322f' + white: '#eee8d5' + yellow: '#b58900' +``` + +To set up a gradient, create a sublevel under accent with two key-value pairs: + +* "left" and "right" or +* "top" and "bottom". + +```yaml +accent: + top: '#abcdef' + bottom: '#fedcba' +``` + +```yaml +accent: + left: '#abcdef' + right: '#fedcba' +``` + +Warp also supports setting a gradient for the background. + +```yaml +# accent has a gradient +accent: + left: '#474747' + right: '#ffffff' +# background has a gradient +background: + top: '#474747' + bottom: '#ffffff' +``` + +### Contributing + +Contributions to this repo are greatly appreciated! + +1. Fork the project +2. Create your branch with `git checkout -b theme/AwesomeTheme` +3. Regenerate thumbnails +4. Commit and open a pull request + +Run this script to generate the thumbnails. + +```bash +# Assuming you're adding the theme to the `standard` directory: +python3 ./scripts/gen_theme_previews.py standard +``` + +:::note +Note: We cannot accept pull requests that include custom background images because: + +* Licensing restrictions +* Trying to keep the binary size of the repo as small as possible (only the yaml files) + +If your theme has an intended custom background image, include a comment in the yaml with a link to where people should download it. +::: + +## Community + +All other Warp-related things can be discussed, please [contact us](/support-and-community/troubleshooting-and-support/sending-us-feedback/). + +## Open source dependencies + +We'd like to call out a few of the open-source themes and repositories that helped bootstrap the set of themes for Warp: + +* [iTerm colors pencil](https://github.com/mattly/iterm-colors-pencil) +* [Alacritty-theme](https://github.com/eendroroy/alacritty-theme) +* [base16-Alacritty](https://github.com/aarowill/base16-alacritty) +* [base16](https://github.com/chriskempson/base16) +* [Solarized](https://ethanschoonover.com/solarized/) +* [Dracula](https://draculatheme.com/) +* [Gruvbox](https://github.com/morhetz/gruvbox) diff --git a/src/content/docs/terminal/appearance/index.mdx b/src/content/docs/terminal/appearance/index.mdx new file mode 100644 index 0000000..a7b3f3c --- /dev/null +++ b/src/content/docs/terminal/appearance/index.mdx @@ -0,0 +1,7 @@ +--- +title: Terminal appearance +description: >- + Customize Warp's visual appearance, including themes, fonts, prompts, app + icons, input position, and pane behavior. +--- + diff --git a/src/content/docs/terminal/appearance/input-position.mdx b/src/content/docs/terminal/appearance/input-position.mdx new file mode 100644 index 0000000..daee932 --- /dev/null +++ b/src/content/docs/terminal/appearance/input-position.mdx @@ -0,0 +1,45 @@ +--- +title: Input position +description: >- + Warp gives you the ability to configure the position of your input, which + includes both the prompt and the command line. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +You can select from three different input positions, which each have different modes of behavior for the flow of input/output Blocks. + +<table><thead><tr><th>Input position</th><th>Behavior</th><th data-hidden></th></tr></thead><tbody><tr><td>Start at the top (Classic mode)</td><td>When you select “start at the top,” the prompt with input will initiate at the top of the view and move down in the view as you enter commands. Blocks of input/output will stack above the prompt and command input. You can scroll up or navigate up to visit past commands. You can enter <code>CTRL-L</code> or the <code>clear</code> command at any time to return the input to the top of the screen while still maintaining your scroll history.</td><td></td></tr><tr><td>Pin to the top (Reverse mode)</td><td>When you select “pin to the top,” the prompt with input will display pinned to the top of your terminal view. Blocks of grouped input/output will flow down the view in reverse order with your latest results at the top. You can scroll down or navigate down to visit past commands. For long-running commands, you can also click "Lock scrolling at bottom of block" to continue to follow the stdout.</td><td></td></tr><tr><td>Pin to the bottom (Warp mode)</td><td>Warp mode starts with input pinned to the bottom of your terminal view. Blocks of grouped input/output flow up and out of view. You can scroll up or navigate up to visit past commands.</td><td></td></tr></tbody></table> + +## How to access it + +* You can configure your input position by navigating to **Settings** > **Appearance** > **Input**. +* You can also choose and set modes from the [Command Palette](/terminal/command-palette/). + +:::note +Changes to the Input position take place immediately and apply to all open panes. +::: + +### Related commands + +<Tabs> + <TabItem label="macOS"> + * `CMD-K` will clear the entire list of input/output blocks for a clean view + * `CTRL-L` will move the list of input/output blocks outside of the view and past the scroll so you have a clean view and the ability to easily visit past commands + * For long Blocks, you can press `SHIFT-CMD-UP`/`SHIFT-CMD-DOWN` to Scroll to the top/bottom the selected block. + </TabItem> + <TabItem label="Windows"> + * `CTRL-SHIFT-K` will clear the entire list of input/output blocks for a clean view + * `CTRL-L` will move the list of input/output blocks outside of the view and past the scroll so you have a clear view and the ability to easily visit past commands + * For long Blocks, you can press `CTRL-SHIFT-UP`/`CTRL-SHIFT-DOWN` to Scroll to the top/bottom of the selected block. + </TabItem> + <TabItem label="Linux"> + * `CTRL-SHIFT-K` will clear the entire list of input/output blocks for a clean view + * `CTRL-L` will move the list of input/output blocks outside of the view and past the scroll so you have a clear view and the ability to easily visit past commands + * For long Blocks, you can press `CTRL-SHIFT-UP`/`CTRL-SHIFT-DOWN` to Scroll to the top/bottom of the selected block. + </TabItem> +</Tabs> + +## How it works + +<VideoEmbed url="https://www.youtube.com/watch?end=147&start=37&v=z1rDVPxaNCo" title="Input Position Demo" /> diff --git a/src/content/docs/terminal/appearance/pane-dimming.mdx b/src/content/docs/terminal/appearance/pane-dimming.mdx new file mode 100644 index 0000000..d2a6551 --- /dev/null +++ b/src/content/docs/terminal/appearance/pane-dimming.mdx @@ -0,0 +1,30 @@ +--- +title: "Pane Dimming & Focus" +description: >- + Warp supports dimming inactive Panes as well as allowing the focus to follow + the mouse. This helps you easily see which pane is active and maintain + focus. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +## How to use it + +### Inactive pane dimming + +The panes that aren't active will be dimmed to better indicate which pane is active. To access it, go to **Settings** > **Appearance** > **Panes** + +* Toggle on **Dim inactive panes** to enable the feature. + +:::note +Split panes show a triangle indicator on the top left corner of the active pane. +::: + +### Mouse focus + +The pane with the mouse over it will become active. To access it, go to **Settings** > **Appearance** > **Panes** + +* Toggle on **Focus follows mouse** to enable the feature. + +## How it works + +<VideoEmbed url="https://www.loom.com/share/62b84d3c60b34cdbaa340fbe8ce8b1d1?hideEmbedTopBar=true&hide_owner=true&hide_share=true&hide_title=true" title="Inactive Pane Dimming Demo" /> diff --git a/src/content/docs/terminal/appearance/prompt.mdx b/src/content/docs/terminal/appearance/prompt.mdx new file mode 100644 index 0000000..5d21770 --- /dev/null +++ b/src/content/docs/terminal/appearance/prompt.mdx @@ -0,0 +1,229 @@ +--- +title: Terminal prompt +description: >- + Configure Warp's native prompt with context chips or use your own Shell + prompt (PS1). +--- +import DemoVideo from '@components/DemoVideo.astro'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +Warp supports two prompt types: the **Warp prompt** and the **Shell prompt (PS1)**. + +## Choosing your prompt type + +To switch your prompt type: + +1. Open **Settings** > **Appearance**. +2. Under **Input**, set **Input type** to **Warp** or **Shell (PS1)**. + +When using the Warp prompt, you can right-click the prompt area to copy the entire prompt, working directory, current git branch, git uncommitted file count, and more. + +When using a Shell prompt, you can right-click the prompt area to copy the entire prompt, or select any part of the prompt in previously run blocks in your session. + +## Warp prompt + +Warp has a native prompt that displays context chips showing information such as your current working directory, git branch, svn status, Kubernetes context, pyenv, date, and time. The Warp prompt is the default when **Input type** is set to **Warp**. + +To customize which context chips your Warp prompt displays: + +1. Right-click the prompt area and select **Edit prompt**. + +![Right-click context menu showing the Edit prompt option](../../../../assets/terminal/edit-prompt-modal.png) + +2. Select **Warp Prompt**. +3. Drag and drop context chips to configure which pieces of information your prompt displays. + +{/* TODO: Add an updated screenshot of the Edit prompt chip customization view (drag-and-drop interface) here, and delete the outdated edit-prompt-modal (1).png from assets. */} + +### Git and Subversion + +Git and Subversion context chips show which branch you are on locally, as well as the number of uncommitted changed files. This includes any new files, modified files, and deleted files that are staged or unstaged. + +### Kubernetes + +The Kubernetes context chip shows relevant information when you're using one of the following commands: + +`kubectl|helm|kubens|kubectx|oc|istioctl|kogito|k9s|helmfile|flux|fluxctl|stern|kubeseal|skaffold|kubent|kubecolor|cmctl|sparkctl|etcd|fubectl` + +:::note +Warp respects the `KUBECONFIG` environment variable. Make sure you set it to your preferred configuration file location if it's not the default path of `~/.kube/config`. +::: + +{/* TODO: Same-line prompt was removed in the current release. May return in a future version (V2/V3). Uncomment when the feature ships. */} +{/* ### Same line prompt + +By default, Warp's prompt displays on two lines where the command-line input is one line below the prompt. + +To enable same-line prompt: + +1. Right-click the prompt area and select **Edit prompt**. +2. Select **Warp Prompt**. +3. Check the box for **Same line prompt**. */} + +## Shell prompt (PS1) + +You can use a Shell prompt instead of the Warp prompt by configuring the **PS1** variable or installing a supported shell prompt plugin (see [Shell Prompt Compatibility Table](/terminal/appearance/prompt/#shell-prompt-compatibility-table)). + +To enable the Shell prompt: + +1. Open **Settings** > **Appearance**. +2. Under **Input**, set **Input type** to **Shell (PS1)**. +3. Configure your PS1 variable in your shell's RC file, or install a supported prompt plugin. + +:::note +The PS1 is a variable used by the shell to generate the prompt, it represents the primary prompt string (hence the "PS") - which the terminal typically displays before typing new commands. +::: + +### Multi-line and right-sided prompts + +The Shell prompt supports multi-line or right-sided prompts in zsh and fish, not bash. However, you can't have a multiline right-side prompt, only a multiline left prompt. + +:::note +If you want to add a new line to your Shell prompt, run the following based on your shell or prompt: + +```sh +# Bash +echo -e '\nPS1="${PS1}"$'\''\\n'\''' >> ~/.bashrc + +# Zsh +echo -e '\nPROMPT="${PROMPT}"$'\''\\n'\''' >> ~/.zshrc + +# Fish +echo -e '\nfunctions --copy fish_prompt fish_prompt_orig; function fish_prompt; fish_prompt_orig; echo; end' >> ~/.config/fish/config.fish + +# Powershell +$rawString = @' +$originalPrompt = Get-Item Function:\prompt +Set-Item -Path Function:\prompt_original -Value $originalPrompt +function prompt { + "$(& prompt_original)`n" +} +'@ +Add-Content -Path $PROFILE -Value "`n$rawString`n" + +# Powerlevel10k +p10k configure + +# Starship Prompt +echo '[line_break]\ndisabled = false' >> ~/.config/starship.toml +``` +::: + +## How it works + +<DemoVideo src="/assets/terminal/warp-custom-prompt-demo.mp4" label="Warp Prompt + Custom Prompt Demo" /> + +{/* Outdated screenshot removed; see TODO after step 3 in the Warp prompt section. */} + +### Shell prompt compatibility table + +| Shell | Tool | Does it work? | +| --------------------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------- | +| bash \| zsh | [PS1](https://www.warp.dev/blog/whats-so-special-about-ps1) | Working | +| bash \| zsh \| fish \| pwsh | [Starship](https://github.com/starship/starship) | [Working\*](/terminal/appearance/prompt/#starship) | +| bash \| zsh \| fish \| pwsh | [oh-my-posh](https://github.com/JanDeDobbeleer/oh-my-posh) | Working | +| zsh | [Powerlevel10k](https://github.com/romkatv/powerlevel10k) | [Working\*](/terminal/appearance/prompt/#powerlevel10k) | +| zsh | [Spaceship](https://github.com/spaceship-prompt/spaceship-prompt) | [Working\*](/terminal/appearance/prompt/#spaceship) | +| zsh | [oh-my-zsh](https://github.com/ohmyzsh/ohmyzsh) | Working | +| zsh | [prezto](https://github.com/sorin-ionescu/prezto) | [Working\*](/terminal/appearance/prompt/#prezto) | +| ssh | | Working | +| bash | [oh-my-bash](https://github.com/ohmybash/oh-my-bash) | Not supported | +| bash | [bash-it](https://github.com/Bash-it/bash-it) | Not supported | +| bash | [SBP](https://github.com/brujoand/sbp) | Not supported | +| bash | [synth-shell-prompt](https://github.com/andresgongora/synth-shell-prompt) | Not supported | +| bash \| zsh | [Powerline-shell](https://github.com/b-ryan/powerline-shell) | Not supported | +| zsh | [zplug](https://github.com/zplug/zplug) | Not supported | +| fish | [tide](https://github.com/IlanCosman/tide) | [Not supported](https://github.com/warpdotdev/Warp/issues/3358) | +| fish | [oh-my-fish](https://github.com/oh-my-fish/oh-my-fish) | [Not supported](https://github.com/warpdotdev/Warp/issues/3796) | + +## Known incompatibilities + +If you're having issues with prompts, please see below or our [Known Issues](/support-and-community/troubleshooting-and-support/known-issues/#configuring-and-debugging-your-rc-files) for more troubleshooting steps. + +### Starship + +#### Starship Settings + +Some `~/.config/starship.toml` settings are known to cause errors in Warp. `#` or `DEL` the following lines to resolve known errors: + +``` +# Get editor completions based on the config schema +'' = 'https://starship.rs/config-schema.json' + +# Disables the custom module +[custom] +disabled = false +``` + +For `fish` shell, optional for `bash|zsh`, disable the multi-line prompt in Starship by putting the following in your `~/.config/starship.toml`: + +``` +[line_break] +disabled = true +``` + +You may also see an error relating to timeout. You can set the `command_timeout` variable in your `~/.config/starship.toml` to fix this. See more in the [starship docs](https://starship.rs/config/#prompt). + +#### Starship + bash + +Starship prompt may not render properly if your [default shell](/getting-started/supported-shells/#changing-what-shell-warp-uses) is `/bin/bash`. To [workaround](https://github.com/warpdotdev/Warp/issues/3066#issuecomment-1548643121) the issue, we recommend you upgrade bash, find the path with `echo $(which bash)`, then put the path in **Settings** > **Features** > **Session** > **"Startup shell for new sessions"**. + +#### Starship + zsh + +If you want to restore the additional line after the Starship prompt on `zsh`, add the following to the bottom of your `~/.zshrc` file: `PROMPT="${PROMPT}"$'\n'` + +### Powerlevel10k + +When installing the Powerlevel10k (P10k) prompt, we recommend you use the [Meslo Nerd Font](https://github.com/romkatv/powerlevel10k/blob/master/font.md).\ +\ +P10K may display the arrow dividers as grey instead of color. The color for those chars is rendered grey due to Warp's minimum contrast setting. To [workaround](https://github.com/warpdotdev/Warp/issues/2851#issuecomment-1605005256) this issue, go to **Settings** > **Appearance** > **Text** > **Enforce minimum contrast** and set it to "Never". + +![Example of the grey dividers in p10k](../../../../assets/terminal/p10k-grey-arrow-prompt.png) + +Warp does support [p10k](https://github.com/romkatv/powerlevel10k#installation) version 1.19.0 and above. Ensure you have the latest version installed and restart Warp after the installation/update of p10k. Then enable the custom prompt as stated [above](/terminal/appearance/prompt/#choosing-your-prompt-type) and it should work. + +:::note +Warp still doesn't fully support some p10k features like transient prompt and visual features like gradients. +::: + +<VideoEmbed url="https://www.youtube.com/watch?t=18s&v=dIV9Cso4Mi8" title="Installing Powerlevel10k" /> + +:::caution +Please note the Installing Powerlevel10k video mentions enabling a custom prompt in **Settings** > **Features** > **Honor users custom prompt (PS1)**, but it's now in **Settings** > **Appearance** > **Input** > **Classic** > **Current prompt** > **Shell Prompt (PS1)** . +::: + +### Spaceship + +This prompt can cause an issue with typeahead in Warp's input editor. To [workaround](https://github.com/warpdotdev/Warp/issues/1973#issuecomment-1340150521) the issue, run `echo "SPACESHIP_PROMPT_ASYNC=FALSE" >>! ~/.zshrc`. + +### Prezto + +Although Warp does have support for prezto's prompt, enabling the [prezto utility module](https://github.com/sorin-ionescu/prezto/blob/master/modules/utility/README.md) in the `.zpreztorc` is not supported as with many other autocompletion [plugins that are incompatible](/support-and-community/troubleshooting-and-support/known-issues/#list-of-incompatible-tools). + +### Disabling unsupported prompts for Warp + +We advise using Warp's default prompt or installing one of the supported tools, see [Compatibility Table](/terminal/appearance/prompt/#shell-prompt-compatibility-table). You can disable unsupported prompts for Warp as such: + +``` +if [[ $TERM_PROGRAM != "WarpTerminal" ]]; then +##### WHAT YOU WANT TO DISABLE FOR WARP - BELOW + + # Unsupported Custom Prompt Code + +##### WHAT YOU WANT TO DISABLE FOR WARP - ABOVE +fi +``` + +#### iTerm2 + +The iTerm2 shell integration breaks Warp and your custom prompt will not be able to be visible with this on. If you're coming from iTerm2 please check your dotfiles for it. We advise disabling the integration for Warp like so: + +``` +if [[ $TERM_PROGRAM != "WarpTerminal" ]]; then +##### WHAT YOU WANT TO DISABLE FOR WARP - BELOW + +test -e "${HOME}/.iterm2_shell_integration.zsh" && source "${HOME}/.iterm2_shell_integration.zsh" + +##### WHAT YOU WANT TO DISABLE FOR WARP - ABOVE +fi +``` diff --git a/src/content/docs/terminal/appearance/size-opacity-blurring.mdx b/src/content/docs/terminal/appearance/size-opacity-blurring.mdx new file mode 100644 index 0000000..e9a2b25 --- /dev/null +++ b/src/content/docs/terminal/appearance/size-opacity-blurring.mdx @@ -0,0 +1,62 @@ +--- +title: "Size, Opacity, & Blurring" +description: >- + Configure window size, opacity, and background blurring to match your visual + preferences. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +## How to use it + +### Window Size + +To access size settings, go to **Settings** > **Appearance** > **Window**. + +* Enable "Open new windows with custom size", Then configure your preferred columns and rows. + +:::note +If [Session Restoration](/terminal/sessions/session-restoration/) is enabled, Warp will restore the size of the last window closed when you quit the app. Either make sure the custom-sized window is the last one closed, or disable Session Restoration to ensure Warp launches with the custom-sized window. +::: + +### Window Opacity + +To access it, go to **Settings** > **Appearance** > **Window** + +* The slider supports setting the opacity value between `1` and `100` where `100` is completely opaque or solid. + +### Window Blurring + +After decreasing Opacity (moving the slider to a value less than `100`), you can also blur the background. + +* On macOS, this is done using the blur slider. Increasing the slider increases the blur radius that's applied to the background image. +* On Windows, this is done by toggling the Acrylic background texture on or off. + +:::caution +On macOS, large blur radiuses may affect performance, especially on Retina displays. + +On Linux, window blurring is not supported. + +On Windows, some graphics drivers may not support rendering transparent or translucent windows. See below for troubleshooting tips. +::: + +## How it works + +<DemoVideo src="/assets/terminal/window_size_demo.mp4" label="Window Size Demo" /> + +<VideoEmbed url="https://www.loom.com/share/22c9ef25392e4a5e80f9e01394c84dc4?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Window Opacity and Blurring Demo" /> + +### Troubleshooting transparency on Windows + +:::note +At the moment, window opacity in Warp on Windows **does not work** in the following circumstances: + +* When using DirectX 12 as the rendering backend +* When using any rendering backend with an Nvidia GPU when "Auto" or "Prefer layered" is selected as the value for "Vulkan/OpenGL present method" in NVIDIA Control Panel > Manage 3D Settings +::: + +Some graphics drivers and rendering backends may not support rendering transparent windows. + +You can select the Vulkan or OpenGL graphics backend to render new Warp windows in the Settings menu, under `Features` > `System` > `Preferred graphics backend`. + +You can also opt to render new Warp windows with an integrated GPU, under `Features` > `System` > `Prefer rendering new windows with integrated GPU (low power)`. diff --git a/src/content/docs/terminal/appearance/tabs-behavior.mdx b/src/content/docs/terminal/appearance/tabs-behavior.mdx new file mode 100644 index 0000000..dc697be --- /dev/null +++ b/src/content/docs/terminal/appearance/tabs-behavior.mdx @@ -0,0 +1,49 @@ +--- +title: Tabs Behavior +description: >- + Customize tab behavior in Warp, including tab indicators, tab bar + visibility, and close button position. +--- +import DemoVideo from '@components/DemoVideo.astro'; + +## Tab indicators + +Tab indicators provide visual cues in the tab bar under certain specific conditions: When the current pane is maximized, when panes or tabs are synchronized, and when a command exits with an error. These indicators serve as quick references. + +### How to toggle tab indicators + +* Navigate to **Settings** > **Appearance** > **Tabs**, and switch the "Show tab indicators" option. +* Utilize the [Command Palette](/terminal/command-palette/), then search for "Tab indicators" to toggle the tab indicators. + +<DemoVideo src="/assets/terminal/tab-indicator-demo.mp4" label="Tab Indicator Demo" /> + +## Tab bar + +The tab bar provides easy navigation between open tabs. By default, the tab bar is visible in windowed mode but hides in fullscreen. To access the tab bar when hidden, hover near the top of the window. You can customize its visibility based on your preferences. + +### How to configure the tab bar + +* Navigate to **Settings** > **Appearance** > **Tabs** > **Show the tab bar** to toggle the visibility of the tab bar. Choose from the following options: + * Always – Keeps the tab bar visible at all times. + * Only on hover – Hides the tab bar in both modes. + * When windowed – Displays the tab bar only in windowed mode. +* Block dividers + +:::note +On macOS, traffic lights will not be shown when in windowed mode if the tab bar is set to show only on hover. +::: + +<DemoVideo src="/assets/terminal/tab-bar-demo.mp4" label="Tab Bar Demo" /> + +## Tab close button + +You can configure the position of the tab close button to be either on the left or right side of the tab. + +### How to configure the tab close button + +Navigate to **Settings** > **Appearance** > **Tabs** > **Tab close button position**, then choose from the following options: + +* Left - the close button will be on the left side of the tab (macOS style) +* Right – the close button will be on the right side of the tab (Windows | Linux style)\ + +<DemoVideo src="/assets/terminal/tab-close-button-demo.mp4" label="Tab close button demo" /> diff --git a/src/content/docs/terminal/appearance/text-fonts-cursor.mdx b/src/content/docs/terminal/appearance/text-fonts-cursor.mdx new file mode 100644 index 0000000..12c01ae --- /dev/null +++ b/src/content/docs/terminal/appearance/text-fonts-cursor.mdx @@ -0,0 +1,58 @@ +--- +title: "Text, Fonts, & Cursor" +description: >- + Warp supports customizing the font and how text is displayed. This can help + improve readability and usability. Warp also supports disabling the blinking + cursor. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +:::note +Once a new font is installed in your system, you need to restart Warp for it to show on the list of options. You may also need to check "View all available system fonts" to see the new font. +::: + +## How to use it + +### Text and Fonts + +To access it, go to **Settings** > **Appearance** > **Text** + +From there you can customize: + +* Font type +* Font weight +* Font size +* Line height +* Use thin strokes + * The default setting prevents text from being blurry on low-DPI displays. + +:::caution +On Linux, Warp does not support the "Use thin stroke" feature. +::: + +* Enforce minimum contrast + * The default setting tweaks named colors to meet accessibility standards. +* Show ligatures in terminal + +:::note +Enabling ligatures can reduce performance. Warps default font, Hack, doesn't yet have ligature support. We recommend font that supports ligatures (e.g. [Fira Code](https://github.com/tonsky/FiraCode)) as a stopgap. +::: + +### Cursor + +To access it, go to **Settings** > **Appearance** > **Cursor** + +From there you can customize: + +* Select the Cursor type to Bar, Block, or Underline. +* Toggle the Blinking cursor or from the [Command Palette](/terminal/command-palette/), type "Cursor blink" and toggle the setting. + +:::note +Cursor type preference is disabled while [Vim keybindings](/terminal/editor/vim/) (vim mode) is active. +::: + +## How it works + +<VideoEmbed url="https://www.loom.com/share/be2fa6ab10a3494a8c57a5431966905b?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Text and Fonts Demo" /> + +<VideoEmbed url="https://www.loom.com/share/6ce3218472894763bb80a26b6c632c4d?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Cursor Demo" /> diff --git a/src/content/docs/terminal/appearance/themes.mdx b/src/content/docs/terminal/appearance/themes.mdx new file mode 100644 index 0000000..a38582a --- /dev/null +++ b/src/content/docs/terminal/appearance/themes.mdx @@ -0,0 +1,97 @@ +--- +title: Terminal themes +description: >- + Warp includes several themes (out-of-box) and also supports setting custom + themes. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import ImageGrid from '@components/ImageGrid.astro'; +import ImageGridItem from '@components/ImageGridItem.astro'; +import themeWarpDark from '../../../../assets/terminal/warp-dark.png'; +import themeWarpLight from '../../../../assets/terminal/warp-light.png'; +import themeDracula from '../../../../assets/terminal/dracula.png'; +import themeSolarizedDark from '../../../../assets/terminal/solarized-dark.png'; +import themeSolarizedLight from '../../../../assets/terminal/solarized-light.png'; +import themeGruvboxDark from '../../../../assets/terminal/gruvbox-dark.png'; +import themeGruvboxLight from '../../../../assets/terminal/gruvbox-light.png'; +import themeJellyfish from '../../../../assets/terminal/jellyfish.png'; +import themeKoi from '../../../../assets/terminal/koi.png'; +import themeLeafy from '../../../../assets/terminal/leafy.png'; +import themeMarble from '../../../../assets/terminal/marble.png'; +import themePinkCity from '../../../../assets/terminal/pink-city.png'; +import themeSnowy from '../../../../assets/terminal/snowy.png'; +import themeDarkCity from '../../../../assets/terminal/dark-city.png'; +import themeRedRock from '../../../../assets/terminal/red-rock.png'; +import themeCyberWave from '../../../../assets/terminal/cyber-wave.png'; +import themeWillowDream from '../../../../assets/terminal/willow-dream.png'; +import themeFancyDracula from '../../../../assets/terminal/fancy-dracula.png'; +import themePhenomenon from '../../../../assets/terminal/phenomenon.png'; +import themeSolarFlare from '../../../../assets/terminal/solar-flare.png'; +import themeAdeberry from '../../../../assets/terminal/adeberry.png'; + +### Theme Picker + +The Theme Picker can be accessed by: + +1. Navigating to **Settings** > **Appearance**. +2. Clicking the Custom Themes (shaded) box. +3. Upon selecting a theme, Warp's appearance will update accordingly. +4. Press the checkmark to save the selection, or the X to revert. + +:::note +The Theme setting persists, meaning Warp will open with the same settings in the next session. +::: + +### Theme Creator + +Automatically create new themes based on a background image. + +1. Go to **Settings** > **Appearance** > **Themes** or search "Open theme picker" within the [Command Palette](/terminal/command-palette/). +2. Click the **+** button in the theme picker. +3. Upload the image and select the background color. +4. Click "Create Theme" to save and accept the new theme. + +### OS Theme Sync + +Warp supports synchronizing your theme with the OS’s light and dark themes. To enable this: + +1. Open the **Settings** > **Appearance** dialog. +2. Click the toggle "Sync with OS". +3. You will then be able to select a specific theme for when the OS is in light mode and dark mode. + +## How it works + +<DemoVideo src="/assets/terminal/theme-picker.mp4" label="Theme picker demo" /> + +<DemoVideo src="/assets/terminal/theme-creator.mp4" label="Theme creator demo" /> + +<DemoVideo src="/assets/terminal/theme-sync-demo.mp4" label="theme os sync demo" /> + +## Default Themes + +By default, Warp ships with these themes: + +<ImageGrid> + <ImageGridItem src={themeWarpDark} label="Warp Dark" /> + <ImageGridItem src={themeWarpLight} label="Warp Light" /> + <ImageGridItem src={themeDracula} label="Dracula" /> + <ImageGridItem src={themeSolarizedDark} label="Solarized Dark" /> + <ImageGridItem src={themeSolarizedLight} label="Solarized Light" /> + <ImageGridItem src={themeGruvboxDark} label="Gruvbox Dark" /> + <ImageGridItem src={themeGruvboxLight} label="Gruvbox Light" /> + <ImageGridItem src={themeJellyfish} label="Jellyfish" /> + <ImageGridItem src={themeKoi} label="Koi" /> + <ImageGridItem src={themeLeafy} label="Leafy" /> + <ImageGridItem src={themeMarble} label="Marble" /> + <ImageGridItem src={themePinkCity} label="Pink City" /> + <ImageGridItem src={themeSnowy} label="Snowy" /> + <ImageGridItem src={themeDarkCity} label="Dark City" /> + <ImageGridItem src={themeRedRock} label="Red Rock" /> + <ImageGridItem src={themeCyberWave} label="Cyber Wave" /> + <ImageGridItem src={themeWillowDream} label="Willow Dream" /> + <ImageGridItem src={themeFancyDracula} label="Fancy Dracula" /> + <ImageGridItem src={themePhenomenon} label="Phenomenon" /> + <ImageGridItem src={themeSolarFlare} label="Solar Flare" /> + <ImageGridItem src={themeAdeberry} label="Adeberry" /> +</ImageGrid> + diff --git a/src/content/docs/terminal/blocks/background-blocks.mdx b/src/content/docs/terminal/blocks/background-blocks.mdx new file mode 100644 index 0000000..bf4dcd0 --- /dev/null +++ b/src/content/docs/terminal/blocks/background-blocks.mdx @@ -0,0 +1,31 @@ +--- +title: Background Blocks +description: >- + How Blocks interact with background process output. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +## What is it + +Commands can start background processes that continue even after they exit. You can also start a background process directly from the shell, such as by running it with `&`. + +If Warp receives output that is likely from a background process, the output goes into a _background block_. Background blocks act like regular blocks, except that they don't have an associated command. + +This lets you use all of Warp's block features with background output, such as sharing and bookmarking. + +## How to use it + +Background blocks are automatically created as needed, in between regular blocks running. If you run commands while a background process is still producing output, that output gets split into multiple blocks interleaved with your commands. + +## How it works + +<VideoEmbed url="https://www.loom.com/share/55bbbd9a8cbf495189260756c717cfb2?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Create Background Blocks" /> + +## Troubleshooting background blocks + +There are some limitations, because Warp doesn't know _which_ process any given output came from: + +* If a background process writes output while a foreground command is running in a regular block, the output goes into that block. +* If there are multiple background processes running at the same time, their output may be mixed together. + +In addition, if you start entering a command while another one is running (typeahead), in some cases Warp will mistake the partial command for background output. The most common cause is editing typeahead when using bash versions older than 4.0 (for example, deleting and re-typing part of it). diff --git a/src/content/docs/terminal/blocks/block-actions.mdx b/src/content/docs/terminal/blocks/block-actions.mdx new file mode 100644 index 0000000..502d15d --- /dev/null +++ b/src/content/docs/terminal/blocks/block-actions.mdx @@ -0,0 +1,116 @@ +--- +title: Block Actions +description: >- + Copy, bookmark, share, search, and filter Blocks using built-in actions. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +## Accessing block actions + +There are 2 ways you can access Block actions. + +1. Hover over a Block and click the kebab (three dots) button on the right-hand side. +2. Right-click a Block. + +<VideoEmbed url="https://www.loom.com/share/3dec25e548d4484aa3dd6437869e2bbf?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Accessing Block Actions" /> + +## Copy input / output of block + +For command blocks, you can `RIGHT-CLICK` on a Block or click the context menu and copy the Block command, output, or both. + +For AI blocks, you can `RIGHT-CLICK` to copy the prompt, output, both or the entire conversation. + +<VideoEmbed url="https://www.loom.com/share/9ad67eca0a8d47afb82cc1acba617f3c?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Copy Block Actions" /> + +## Sharing a block + +Share a block easily with coworkers or teammates by creating a web permalink. This preserves formatting and makes debugging and sharing output easy. [See Block Sharing Page.](/terminal/blocks/block-sharing/) + +## Bookmarking a block + +Quickly navigate to important Blocks despite where they are in the terminal history. + +<Tabs> + <TabItem label="macOS"> + Ways to bookmark a Block: + + 1. Select **Toggle bookmark** in the block context menu + 2. Use `CMD-B` keybinding to bookmark a selected block + + Navigate to a bookmarked Block, by: + + * Clicking on the indicator.\ + The indicator position reflects the approximate position of the Block in the Block history. Hovering over the indicator will give a snapshot of the Block including its prompt, command, and the last two lines of output. + * Pressing `OPTION-UP` and `OPTION-DOWN` + </TabItem> + <TabItem label="Windows"> + There are Ways to bookmark a Block: + + 1. Select **Toggle bookmark** in the block context menu + 2. Use `CTRL-SHIFT-B` keybinding to bookmark a selected block + + Navigate to a bookmarked Block, by: + + * Clicking on the indicator.\ + The indicator position reflects the approximate position of the Block in the Block history. Hovering over the indicator will give a snapshot of the Block including its prompt, command, and the last two lines of output. + * Pressing `ALT-UP` and `ALT-DOWN` + </TabItem> + <TabItem label="Linux"> + Ways to bookmark a Block: + + 1. Click on the bookmark icon in the top right corner of a Block + 2. Select **Toggle bookmark** in the block context menu + 3. Use `CTRL-SHIFT-B` keybinding to bookmark a selected block + + Navigate to a bookmarked Block, by: + + * Clicking on the indicator.\ + The indicator position reflects the approximate position of the Block in the Block history. Hovering over the indicator will give a snapshot of the Block including its prompt, command, and the last two lines of output. + * Pressing `ALT-UP` and `ALT-DOWN` + </TabItem> +</Tabs> + +:::note +Bookmarks only persist while the session is open, once you close the session they are lost. If you want to save the command and output for later use, [Share the Block](/terminal/blocks/block-sharing/). +::: + +<DemoVideo src="/assets/terminal/block-bookmarks.mp4" label="Bookmarking a Block" /> + +## Search within a block + +Quickly find important information within a Block. [See Find page](/terminal/blocks/find/) + +<Tabs> + <TabItem label="macOS"> + With a Block selected, press "Find Within Block" or use `CMD-F` to search within a Block. + </TabItem> + <TabItem label="Windows"> + With a Block selected, Press "Find Within Block" or use `CTRL-SHIFT-F` to search within a Block. + </TabItem> + <TabItem label="Linux"> + With a Block selected, Press "Find Within Block" or use `CTRL-SHIFT-F` to search within a Block. + </TabItem> +</Tabs> + +<VideoEmbed url="https://www.loom.com/share/7dda0e7a6ec144cfb6410d29a586ddd0?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Search within a Block" /> + +## Filtering a block + +Filter the output lines of a block natively in Warp to quickly focus on a subset of the block. [See Block Filtering Page](/terminal/blocks/block-filtering/). + +<Tabs> + <TabItem label="macOS"> + * Using the keybinding `OPT-SHIFT-F` by default to toggle filtering on the selected or latest block + * Selecting `Toggle Block Filter` in the block context menu + </TabItem> + <TabItem label="Windows"> + * Using the keybinding `ALT-SHIFT-F` to toggle filtering on the selected or latest block + * Selecting `Toggle Block Filter` in the block context menu + </TabItem> + <TabItem label="Linux"> + * Using the keybinding `ALT-SHIFT-F` to toggle filtering on the selected or latest block + * Selecting `Toggle Block Filter` in the block context menu + </TabItem> +</Tabs> diff --git a/src/content/docs/terminal/blocks/block-basics.mdx b/src/content/docs/terminal/blocks/block-basics.mdx new file mode 100644 index 0000000..99ade3c --- /dev/null +++ b/src/content/docs/terminal/blocks/block-basics.mdx @@ -0,0 +1,119 @@ +--- +title: Terminal Block Basics +description: >- + The basics of creating, selecting, and navigating between Blocks. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +## The basics + +* Blocks group your command and command output +* The Input Editor can pin to the bottom, pin to the top, or start at the top. +* Blocks grow from the bottom to the top. +* Blocks are color-coded. Blocks that quit with a non-zero exit code have a red background and red sidebar. + +:::note +Try it yourself!\ +Type `xyz` (or some other command that doesn’t exist) and hit `ENTER` +::: + +## Create a block + +1. Execute a command (type `ls` and hit `ENTER`) in the Input Editor at the bottom of the screen. +2. Your command and output are grouped into a Block. +3. Try executing a different command (type `echo hello` and hit `ENTER`). +4. Warp adds your newly created Block to the bottom (directly above the input editor). + +<VideoEmbed url="https://www.loom.com/share/4b435c78344d4dc0bb92af5d1da5e219?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Create a Block" /> + +## Select a single block + +<Tabs> + <TabItem label="macOS"> + * Using your mouse: click on a Block. + * Or using your keyboard: hit `CMD-UP` (or `CMD-DOWN` if input as pinned up top) to select the most recently executed Block and use the `UP ↑` and `DOWN ↓` arrow keys to navigate to the desired Block. + * For long Blocks: + * You can click "Jump to the bottom of this block". + * You can press `SHIFT-CMD-UP`/`SHIFT-CMD-DOWN` to Scroll to the top/bottom of the selected block. + * From the [Command Palette](/terminal/command-palette/), you can also "Scroll to the top/bottom of selected block". + </TabItem> + <TabItem label="Windows"> + * Using your mouse: Click on a Block. + * Or using your keyboard: hit `CTRL-UP` (or `CTRL-DOWN` if input as pinned up top) to select the most recently executed Block and use the `UP ↑` and `DOWN ↓` arrow keys to navigate to the desired Block. + * For long Blocks: + * You can click "Jump to the bottom of this block". + * You can press `CTRL-SHIFT-UP`/`CTRL-SHIFT-DOWN` to Scroll to the top/bottom of the selected block. + * From the [Command Palette](/terminal/command-palette/), you can also "Scroll to the top/bottom of selected block". + </TabItem> + <TabItem label="Linux"> + * Using your mouse: Click on a Block. + * Or using your keyboard: hit `CTRL-UP` (or `CTRL-DOWN` if input as pinned up top) to select the most recently executed Block and use the `UP ↑` and `DOWN ↓` arrow keys to navigate to the desired Block. + * For long Blocks: + * You can click "Jump to the bottom of this block". + * You can press `CTRL-SHIFT-UP`/`CTRL-SHIFT-DOWN` to Scroll to the top/bottom of the selected block. + * From the [Command Palette](/terminal/command-palette/), you can also "Scroll to the top/bottom of selected block". + </TabItem> +</Tabs> + +<VideoEmbed url="https://www.loom.com/share/1cf8546daad548fbbe056c35edb23cdc?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Select a Single Block" /> + +## Select multiple blocks + +<Tabs> + <TabItem label="macOS"> + * Click another Block while holding `CMD` to toggle the selection of that Block, or + * Click another Block while holding `SHIFT` to select a range of Block, or + * Use `SHIFT-UP ↑` or `SHIFT-DOWN ↓` to expand the active selection (the Block with the thicker border) up or down, respectively. + </TabItem> + <TabItem label="Windows"> + * Click another Block while holding `CTRL-SHIFT` to toggle the selection of that Block, or + * Click another Block while holding `SHIFT` to select a range of Block, or + * Use `SHIFT-UP ↑` or `SHIFT-DOWN ↓` to expand the active selection (the Block with the thicker border) up or down, respectively. + </TabItem> + <TabItem label="Linux"> + * Click another Block while holding `CTRL-SHIFT` to toggle the selection of that Block, or + * Click another Block while holding `SHIFT` to select a range of Block, or + * Use `SHIFT-UP ↑` or `SHIFT-DOWN ↓` to expand the active selection (the Block with the thicker border) up or down, respectively. + </TabItem> +</Tabs> + +<VideoEmbed url="https://www.loom.com/share/5058ab0dc3d244d4a2ce576331440821?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Select Multiple Blocks" /> + +## Navigate blocks + +<Tabs> + <TabItem label="macOS"> + * **Mouse or scrollbar** - Scroll using your mouse, trackpad, or the scrollbar. + * **Arrow keys** - Select a Block and use `UP ↑` and `DOWN ↓` to move between Blocks. + * **Page scrolling** - Press `PAGE UP` or `PAGE DOWN` to scroll by one page. + * **Jump to top or bottom** - Press `HOME` or `END` to scroll to the top or bottom of terminal output. + * **Scroll within a selected Block** - Press `SHIFT-CMD-UP` or `SHIFT-CMD-DOWN` to scroll to the top or bottom of the selected Block. + * **Scroll one line at a time** - "Scroll Terminal output up/down one line" can be configured with a keyboard shortcut in Settings > Keyboard shortcuts or accessed from the [Command Palette](/terminal/command-palette/). + * When the output of a command is cut off, Warp keeps the [Sticky Command Header](/terminal/blocks/sticky-command-header/) pinned at the top that displays the command the Block corresponds to. Clicking the header will scroll the screen to the start of the Block. + </TabItem> + <TabItem label="Windows"> + * **Mouse or scrollbar** - Scroll using your mouse, trackpad, or the scrollbar. + * **Arrow keys** - Select a Block and use `UP ↑` and `DOWN ↓` to move between Blocks. + * **Page scrolling** - Press `PAGE UP` or `PAGE DOWN` to scroll by one page. + * **Jump to top or bottom** - Press `HOME` or `END` to scroll to the top or bottom of terminal output. + * **Scroll within a selected Block** - Press `CTRL-SHIFT-UP` or `CTRL-SHIFT-DOWN` to scroll to the top or bottom of the selected Block. + * **Scroll one line at a time** - "Scroll Terminal output up/down one line" can be configured with a keyboard shortcut in Settings > Keyboard shortcuts or accessed from the [Command Palette](/terminal/command-palette/). + * When the output of a command is cut off, Warp keeps the [Sticky Command Header](/terminal/blocks/sticky-command-header/) pinned at the top that displays the command the Block corresponds to. Clicking the header will scroll the screen to the start of the Block. + </TabItem> + <TabItem label="Linux"> + * **Mouse or scrollbar** - Scroll using your mouse, trackpad, or the scrollbar. + * **Arrow keys** - Select a Block and use `UP ↑` and `DOWN ↓` to move between Blocks. + * **Page scrolling** - Press `PAGE UP` or `PAGE DOWN` to scroll by one page. + * **Jump to top or bottom** - Press `HOME` or `END` to scroll to the top or bottom of terminal output. + * **Scroll within a selected Block** - Press `CTRL-SHIFT-UP` or `CTRL-SHIFT-DOWN` to scroll to the top or bottom of the selected Block. + * **Scroll one line at a time** - "Scroll Terminal output up/down one line" can be configured with a keyboard shortcut in Settings > Keyboard shortcuts or accessed from the [Command Palette](/terminal/command-palette/). + * When the output of a command is cut off, Warp keeps the [Sticky Command Header](/terminal/blocks/sticky-command-header/) pinned at the top that displays the command the Block corresponds to. Clicking the header will scroll the screen to the start of the Block. + </TabItem> +</Tabs> + +:::note +During long-running or full-screen commands, `PAGE UP`, `PAGE DOWN`, `HOME`, and `END` are forwarded to the running program. See the full list of scrolling shortcuts on the [Keyboard Shortcuts](/getting-started/keyboard-shortcuts/) page. +::: + +<VideoEmbed url="https://www.loom.com/share/21ebb0a79c1248a98846cba12a4b7020?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Navigate between Blocks" /> diff --git a/src/content/docs/terminal/blocks/block-filtering.mdx b/src/content/docs/terminal/blocks/block-filtering.mdx new file mode 100644 index 0000000..785f3fb --- /dev/null +++ b/src/content/docs/terminal/blocks/block-filtering.mdx @@ -0,0 +1,48 @@ +--- +title: Block Filtering +description: >- + Filter Block output by text, regex, or case to focus on specific matching + lines. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +Filter the output lines of a block in Warp to quickly focus on a subset of the block. You can filter by plaintext, regex, invert, or make your filter case-sensitive. You can also add context lines to view output around matches. Filtering does not delete any output lines, so you can clear the filter to go back to the original output. + +## How to filter a block + +To apply a filter to a block: + +1. Click on the filter icon in the top right corner of a block. A filter editor will appear with a large input field with two buttons on the left and a smaller input field on the right. +2. Type in the input to filter the block in the left input field. Only lines containing text that matches the filter query will be shown. +3. (Optional) Click on the regex, case sensitive search, or invert filter buttons to enable. +4. (Optional) Type a number in the right input field to add context lines around matched lines. + +<DemoVideo src="/assets/terminal/block_filtering_with_context_lines.mp4" label="Filter a block's output, with the ability to add context lines." /> + +<Tabs> + <TabItem label="macOS"> + You can also toggle a filter by: + + * Using the keybinding `OPT-SHIFT-F` by default to toggle filtering on the selected or latest block + * Selecting `Toggle Block Filter` in the block context menu + </TabItem> + <TabItem label="Windows"> + You can also toggle a filter on/off by: + + * Using the keybinding `ALT-SHIFT-F` to toggle filtering on the selected or latest block + * Selecting `Toggle Block Filter` in the block context menu + </TabItem> + <TabItem label="Linux"> + You can also toggle a filter on/off by: + + * Using the keybinding `ALT-SHIFT-F` to toggle filtering on the selected or latest block + * Selecting `Toggle Block Filter` in the block context menu + </TabItem> +</Tabs> + +:::note +Toggling a filter on a block without a filter applied will open the filter editor. If you toggle a filter off, the same filter will be applied if you toggle filtering on again. +::: + +<DemoVideo src="/assets/terminal/block_filtering_toggle.mp4" label="Toggle a block filter on/off." /> diff --git a/src/content/docs/terminal/blocks/block-sharing.mdx b/src/content/docs/terminal/blocks/block-sharing.mdx new file mode 100644 index 0000000..304ba18 --- /dev/null +++ b/src/content/docs/terminal/blocks/block-sharing.mdx @@ -0,0 +1,83 @@ +--- +title: Block Sharing +description: >- + Share Blocks with your team as permalinks or embeddable HTML snippets. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +:::note +This action sends command information to our server and is explicitly opt-in. Read more about privacy at Warp on [our privacy page](https://www.warp.dev/privacy). +::: + +Share your blocks with a permalink or HTML embed. You can get started with shared blocks by opening the context menu and copying the command, output, or prompt. + +## How to share blocks + +<Tabs> + <TabItem label="macOS"> + To share your blocks, follow these steps: + + 1. On a finished block, click the context menu and select **Share...** or select the block and hit `CMD-SHIFT-S`. + 2. A modal will pop up that lets you title your block and customize it by selecting which parts of the block you want to share (e.g. command, output, prompt, etc.). + 3. Click either "Create link" or "Get embed" depending on how you want to share your block. + 4. The link or embed snippet will be copied to your clipboard. + </TabItem> + <TabItem label="Windows"> + To share your blocks, follow these steps: + + 1. On a finished block, click the context menu and select **Share...** or by setting up a key bind for Share Block in **Settings** > **Keyboard shortcuts**. + 2. A modal will pop up that lets you title your block and customize it by selecting which parts of the block you want to share (e.g. command, output, prompt, etc.). + 3. Click either "Create link" or "Get embed" depending on how you want to share your block. + 4. The link or embed snippet will be copied to your clipboard. + </TabItem> + <TabItem label="Linux"> + To share your blocks, follow these steps: + + 1. On a finished block, click the context menu and select **Share...** or by setting up a key bind for Share Block in **Settings** > **Keyboard shortcuts**. + 2. A modal will pop up that lets you title your block and customize it by selecting which parts of the block you want to share (e.g. command, output, prompt, etc.). + 3. Click either "Create link" or "Get embed" depending on how you want to share your block. + 4. The link or embed snippet will be copied to your clipboard. + </TabItem> +</Tabs> + +:::note +If you experience any issues with block sharing, please see our known issues for [troubleshooting steps](/support-and-community/troubleshooting-and-support/known-issues/#online-features-dont-work). +::: + +<DemoVideo src="/assets/terminal/block-sharing-embed.mp4" label="Block Sharing & Embed Demo" /> + +## Permalink + +Create and share a permalink to your blocks to collaborate with teammates. Here is the [web permalink](https://app.warp.dev/block/vzFATak939iqGWfNh7wsAP) of the block depicted below. + +![Shared Block](../../../../assets/terminal/shared_block.png) + +## Embedded blocks + +Create and embed your blocks on web pages to help your readers follow along with technical writing. Readers can interact with an embedded block as they would with a block in Warp, with a context menu and styling. When you click "Get embed", Warp will copy an `iframe` to your clipboard. Here's an example `iframe`: + +```html +<iframe src="https://app.warp.dev/block/embed/qn0g1CqQnkYjEafPH5HCVT" +title="server script error" style="width: 712px; height: 397px; border:0; +overflow:hidden;" allow="clipboard-read; clipboard-write"></iframe> +``` + +#### Embedded block example on web page + +![Embedded Block Example](../../../../assets/terminal/embed.png) + +## Managing shared blocks + +You can unshare a block by navigating to **Settings** > **Shared blocks**. Currently, shared blocks are accessible to anyone with the link. + +## Link previews + +Shared permalinks will also display a preview of your code for quick context on each link. + +:::note +Compatible with any platform that supports Open Graph or Twitter meta tags. For example Slack, Twitter, Facebook, Telegram, Notion, and more ... +::: + +<VideoEmbed url="https://www.loom.com/share/a78147fee8804c00b08a1decbc0d4e72?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Share and Unfurl a Block Preview" /> diff --git a/src/content/docs/terminal/blocks/find.mdx b/src/content/docs/terminal/blocks/find.mdx new file mode 100644 index 0000000..1597bc9 --- /dev/null +++ b/src/content/docs/terminal/blocks/find.mdx @@ -0,0 +1,37 @@ +--- +title: Terminal Block Find +description: >- + Search across Blocks from the bottom up, with regex, case-sensitive, and + per-Block filtering options. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +## What is it + +Find searches for matches in all your Blocks from the bottom up and can even be isolated to a specific Block. + +:::note +Since command outputs are contained within Blocks, you can still use the input editor when invoking find. +::: + +## How to access it + +<Tabs> + <TabItem label="macOS"> + 1. Hitting `CMD-F` opens the find view which searches across the terminal (scoped within the current pane). + 2. Within the find modal, you can also enable the regex toggle, find on a selected Block, and or toggle case sensitive search. + </TabItem> + <TabItem label="Windows"> + 1. Hitting `CTRL-SHIFT-F` opens the find view which searches across the terminal (scoped within the current pane). + 2. Within the find modal, you can also enable the regex toggle, find on a selected Block, and or toggle case sensitive search. + </TabItem> + <TabItem label="Linux"> + 1. Hitting `CTRL-SHIFT-F` opens the find view which searches across the terminal (scoped within the current pane). + 2. Within the find modal, you can also enable the regex toggle, find on a selected Block, and or toggle case sensitive search. + </TabItem> +</Tabs> + +## How it works + +<DemoVideo src="/assets/terminal/find.mp4" label="Searching across Warp's terminal blocks with the Find view" /> diff --git a/src/content/docs/terminal/blocks/index.mdx b/src/content/docs/terminal/blocks/index.mdx new file mode 100644 index 0000000..8ae559e --- /dev/null +++ b/src/content/docs/terminal/blocks/index.mdx @@ -0,0 +1,25 @@ +--- +title: Terminal Blocks +description: >- + A Block groups commands and outputs into one atomic unit. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +## What are Blocks? + +Blocks enable us to easily: + +* Copy a command +* Copy a command’s output +* Scroll directly to the start of a command’s output +* Re-input commands +* Share both a command and its output (with formatting!) +* Bookmark commands + +:::note +Interested in how we differentiate input and output, or how we implement blocks? Check out our blog post: [How Warp Works.](https://blog.warp.dev/how-warp-works/#implementing-blocks) +::: + +<VideoEmbed url="https://youtu.be/PH1u0TZ5Lf0" title="Intro to Blocks" /> + +![Blocks](../../../../assets/terminal/annotated_blocks-1.png) diff --git a/src/content/docs/terminal/blocks/sticky-command-header.mdx b/src/content/docs/terminal/blocks/sticky-command-header.mdx new file mode 100644 index 0000000..ff6e187 --- /dev/null +++ b/src/content/docs/terminal/blocks/sticky-command-header.mdx @@ -0,0 +1,47 @@ +--- +title: Sticky Command Header +description: >- + Pin the running command at the top of the screen when scrolling through + large Block outputs. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +:::note +For long-running commands that take up the full screen, the sticky header only shows after you start scrolling up. This is to prevent the header from blocking the top part of the output for commands like `git log` that simulate full-screen apps. +::: + +## How to access Sticky Command Header + +<Tabs> + <TabItem label="macOS"> + * Sticky Command Header is enabled by default. + * Toggle Sticky Command Header by going to **Settings** > **Features** > **General** > toggle “Show sticky command header”. + * Toggle by searching for “Sticky Command Header” within the [Command Palette](/terminal/command-palette/) or by pressing `CTRL-CMD-S`. + * You can also "Toggle Sticky Command Header in Active Pane" with `CTRL-S`. This won't disable the feature entirely, only minimize it on the active session. + </TabItem> + <TabItem label="Windows"> + * Sticky Command Header is enabled by default. + * Toggle the Sticky Command Header by going to **Settings** > **Features** > **General** > toggle “Show sticky command header”. + * Toggle by searching for “Sticky Command Header” within the [Command Palette](/terminal/command-palette/) or by setting up a key bind in **Settings** > **Keyboard shortcuts**. + * You can also "Toggle Sticky Command Header in Active Pane" in the Command Palette or by setting up a key bind in **Settings** > **Keyboard shortcuts**. This won’t disable the feature entirely, only minimize it on the active session. + </TabItem> + <TabItem label="Linux"> + * Sticky Command Header is enabled by default. + * Toggle the Sticky Command Header by going to **Settings** > **Features** > **General** > toggle “Show sticky command header”. + * Toggle by searching for “Sticky Command Header” within the [Command Palette](/terminal/command-palette/) or by setting up a key bind in**Settings** > **Keyboard shortcuts**. + * You can also "Toggle Sticky Command Header in Active Pane" in the Command Palette or by setting up a key bind in**Settings** > **Keyboard shortcuts**. This won't disable the feature entirely, only minimize it on the active session. + </TabItem> +</Tabs> + +## How to use Sticky Command Header + +* If a Block has a large output ( e.g. `seq 1 1000`), the header of the Block will show on the top of the active Window, Tab, or Pane. +* Click on the Sticky Command Header to quickly jump to the top of the Block. +* While active you can also minimize the Sticky Command Header on the active pane by clicking the UP/DOWN arrow in the middle of the header. + +## How Sticky Command Header works + +<VideoEmbed url="https://www.loom.com/share/a86967c057e44ab4bee4860ba80538b9?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Sticky Command Header Demo" /> + +![Toggle active header and Jump to bottom of block demo](/assets/terminal/sticky-header-toggle-active-demo.gif) diff --git a/src/content/docs/terminal/command-completions/autosuggestions.mdx b/src/content/docs/terminal/command-completions/autosuggestions.mdx new file mode 100644 index 0000000..d16c2e0 --- /dev/null +++ b/src/content/docs/terminal/command-completions/autosuggestions.mdx @@ -0,0 +1,48 @@ +--- +title: Autosuggestions +description: >- + Warp will automatically suggest commands as you type based on shell history + and possible completions. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +## How to access it + +* From the [Command Palette](/terminal/command-palette/), type in "Autosuggestions" to toggle. + +:::note +**Terminal Tip** + +You can change the keybinding for accepting autosuggestions to `Tab`. Configure this in the "Tab key behavior" setting under **Settings** > **Features** > **Terminal Input**. _Note: This will update the keybinding for opening the completions menu to `CTRL-SPACE`. You can also enable the "Open completions menu as you type" in **Settings** > **Features** > **Terminal Input** so that the completions menu opens automatically._ +::: + +## How to use it + +<Tabs> + <TabItem label="macOS"> + There are several ways to accept autosuggestions, either completely or partially: + + * Complete an autosuggestion using the `RIGHT` arrow or `CTRL-F`. + * `CTRL-E` also, completes the autosuggestion when your cursor is at the end of the buffer. + * `CTRL-RIGHT` can be used to partially complete the autosuggestion one component at a time. + </TabItem> + <TabItem label="Windows"> + There are several ways to accept autosuggestions, either completely or partially: + + * Complete an autosuggestion using the `RIGHT` arrow or `CTRL-F`. + * `END` jumps to the last character in the Input Editor, then `RIGHT` completes the autosuggestion. + * `CTRL-SHIFT-RIGHT` can be used to partially complete the autosuggestion one component at a time. + </TabItem> + <TabItem label="Linux"> + There are several ways to accept autosuggestions, either completely or partially: + + * Complete an autosuggestion using the `RIGHT` arrow or `CTRL-F`. + * `CTRL-E` jumps to the last character in the Input Editor, then `RIGHT` completes the autosuggestion. + * `CTRL-SHIFT-RIGHT` can be used to partially complete the autosuggestion one component at a time. + </TabItem> +</Tabs> + +## How it works + +<VideoEmbed url="https://www.loom.com/share/5e87c52ae855486ab88ffb2f89aeaf73?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Autosuggestion Demo" /> diff --git a/src/content/docs/terminal/command-completions/completions.mdx b/src/content/docs/terminal/command-completions/completions.mdx new file mode 100644 index 0000000..2fde8bc --- /dev/null +++ b/src/content/docs/terminal/command-completions/completions.mdx @@ -0,0 +1,507 @@ +--- +title: Tab completions +description: >- + Get fuzzy-matched suggestions for commands, options, and paths by pressing + Tab anywhere. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +## What is it + +Completions feature fuzzy search capability that provides you with [approximate matches](https://en.wikipedia.org/wiki/Approximate_string_matching) for your queries. If you're unsure about the exact syntax or spelling, you'll be provided with suggestions based on your input, even if it's not an exact match. + +## How to access it + +* Type out the beginning of your command, then press `TAB`. +* To search for options and flags, you must type and press `TAB`. +* Forgo `TAB` by enabling "Open completions menu as you type" in **Settings** > **Features** > **Terminal Input** + +## How to use it + +### Completions + +1. Type `git checkout` (note the space) and then press `TAB` +2. A menu will show all of your local branches. You can select one using your mouse or the `UP ↑`/`DOWN ↓` arrow keys + +### Completions on Aliases + +* Shell aliases - This is an alias for an entire command. For example, if you have `gc=git checkout` in alias, typing `gc` and hitting `TAB` should give you the same completion options as for `git checkout` . +* Command aliases - This is an alias for a subcommand. For example, this could be setting `git status` to `git st`. With completions support, we could now suggest completions for `git status` even if you typed in `git st`. + +:::note +**Terminal Tip**\ +The "Tab key behavior" setting under **Settings** > **Features** > **Terminal Input** can change the action that `Tab` is bound to. If `Tab` is not bound to open the completions menu, `ctrl-space` will be assigned as the default keybinding. _Note: You can also enable the "Open completions menu as you type" in **Settings** > **Features** > **Terminal Input** so that the completions menu opens automatically._ +::: + +## How it works + +<VideoEmbed url="https://www.loom.com/share/92594c821ae341f69d5d1c1af56f2c69?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Completions Demo" /> + +### Supported completion specs + +| Command Name | Level of Support | +| ----------------------- | ---------------- | +| act | Partial | +| adb | Partial | +| afplay | Partial | +| aftman | Partial | +| ag | Partial | +| agrippa | Partial | +| amplify | Partial | +| ansible | Partial | +| ansible-config | Partial | +| ansible-doc | Partial | +| ansible-galaxy | Partial | +| ansible-lint | Partial | +| ansible-playbook | Partial | +| appwrite | Partial | +| arch | Partial | +| asdf | Partial | +| assimp | Partial | +| atlas | Partial | +| autojump | Partial | +| aws | Partial | +| babel | Partial | +| banner | Partial | +| base32 | Partial | +| base64 | Partial | +| basename | Partial | +| basenc | Partial | +| bat | Partial | +| bazel | Partial | +| bc | Partial | +| black | Partial | +| blitz | Partial | +| bosh | Full | +| brew | Full | +| build-storybook | Partial | +| bun | Partial | +| bundle | Partial | +| bw | Partial | +| caffeinate | Partial | +| cargo | Full | +| cat | Partial | +| cd | Partial | +| cdk | Partial | +| checkov | Partial | +| chmod | Partial | +| chown | Partial | +| circleci | Partial | +| clang | Partial | +| clear | Partial | +| clojure | Partial | +| cloudflared | Partial | +| cmake | Partial | +| code | Partial | +| code-insiders | Partial | +| command | Partial | +| composer | Partial | +| conda | Full | +| copilot | Partial | +| cordova | Partial | +| cosign | Partial | +| cot | Partial | +| cp | Partial | +| create-completion-spec | Partial | +| create-next-app | Partial | +| create-nx-workspace | Partial | +| create-react-app | Partial | +| create-react-native-app | Partial | +| create-remix | Partial | +| create-t3-app | Partial | +| create-video | Partial | +| create-web3-frontend | Partial | +| croc | Partial | +| curl | Partial | +| cut | Partial | +| dart | Partial | +| date | Partial | +| dateseq | Partial | +| datree | Partial | +| dbt | Partial | +| dd | Partial | +| defaults | Full | +| degit | Partial | +| deno | Partial | +| deployctl | Partial | +| deta | Partial | +| df | Partial | +| diff | Partial | +| dig | Partial | +| direnv | Partial | +| dirname | Partial | +| django-admin | Partial | +| do | Partial | +| docker | Full | +| docker-compose | Partial | +| doctl | Partial | +| dog | Partial | +| doppler | Partial | +| dotenv | Partial | +| dotnet | Partial | +| dotslash | Partial | +| drush | Partial | +| dtm | Partial | +| du | Partial | +| eb | Partial | +| echo | Partial | +| electron | Partial | +| eleventy | Partial | +| elif | Partial | +| elixir | Partial | +| elm | Partial | +| elm-review | Partial | +| else | Partial | +| emacs | Partial | +| esbuild | Partial | +| eslint | Partial | +| exa | Partial | +| exec | Partial | +| exercism | Partial | +| expo | Partial | +| expo-cli | Partial | +| export | Partial | +| fastlane | Partial | +| fastly | Partial | +| fd | Partial | +| ffmpeg | Partial | +| fig-teams | Partial | +| file | Partial | +| find | Partial | +| firebase | Full | +| fisher | Partial | +| flutter | Full | +| fly | Partial | +| flyctl | Partial | +| fmt | Partial | +| fnm | Partial | +| fold | Partial | +| for | Partial | +| forge | Partial | +| fvm | Partial | +| fzf | Partial | +| fzf-tmux | Partial | +| ganache-cli | Partial | +| gatsby | Partial | +| gcc | Partial | +| gcloud | Partial | +| gh | Full | +| git | Full | +| git-flow | Partial | +| github | Partial | +| gltfjsx | Partial | +| go | Full | +| goctl | Partial | +| googler | Partial | +| goreleaser | Partial | +| gpg | Partial | +| gradle | Partial | +| graphcdn | Partial | +| grep | Partial | +| grex | Partial | +| hardhat | Partial | +| hasura | Partial | +| hb-service | Partial | +| head | Partial | +| helm | Partial | +| heroku | Full | +| hexo | Partial | +| hostname | Partial | +| htop | Partial | +| http | Partial | +| https | Partial | +| httpy | Partial | +| hub | Partial | +| hugo | Partial | +| hx | Partial | +| hyper | Partial | +| id | Partial | +| iex | Partial | +| if | Partial | +| ignite-cli | Partial | +| install | Partial | +| ionic | Partial | +| j | Partial | +| java | Partial | +| jest | Partial | +| join | Partial | +| jq | Partial | +| julia | Partial | +| jupyter | Partial | +| just | Partial | +| keytool | Partial | +| kill | Partial | +| killall | Full | +| kitty | Partial | +| knex | Partial | +| kool | Partial | +| kubecolor | Partial | +| kubectl | Full | +| kubectx | Full | +| kubens | Full | +| laravel | Partial | +| lerna | Partial | +| less | Partial | +| lima | Partial | +| limactl | Partial | +| ln | Partial | +| lp | Partial | +| lpass | Partial | +| ls | Partial | +| lsd | Partial | +| mackup | Partial | +| make | Full | +| man | Full | +| mas | Partial | +| mask | Partial | +| mdfind | Partial | +| meteor | Partial | +| micro | Partial | +| mikro-orm | Partial | +| minikube | Partial | +| mix | Partial | +| mkdir | Partial | +| mkfifo | Partial | +| mknod | Partial | +| mob | Partial | +| molecule | Partial | +| mongocli | Partial | +| mongosh | Partial | +| more | Partial | +| mosh | Partial | +| mv | Partial | +| mvn | Partial | +| mysql | Partial | +| n | Partial | +| nano | Partial | +| nativescript | Partial | +| nc | Partial | +| nest | Partial | +| netlify | Partial | +| networkQuality | Partial | +| newman | Partial | +| next | Partial | +| ng | Full | +| nginx | Partial | +| ngrok | Partial | +| nhost | Partial | +| ni | Partial | +| nl | Partial | +| nocorrect | Partial | +| node | Full | +| noglob | Partial | +| npm | Full | +| npx | Partial | +| nr | Partial | +| nrm | Partial | +| ns | Partial | +| nu | Partial | +| nuxi | Partial | +| nuxt | Partial | +| nvim | Partial | +| nvm | Partial | +| nx | Full | +| nylas | Partial | +| od | Partial | +| oh-my-posh | Partial | +| okta | Partial | +| okteto | Partial | +| omz | Partial | +| onboardbase | Partial | +| op | Partial | +| opa | Partial | +| open | Partial | +| osascript | Partial | +| pageres | Partial | +| pandoc | Partial | +| pass | Partial | +| paste | Partial | +| pathchk | Partial | +| pdfunite | Partial | +| pgcli | Partial | +| php | Partial | +| phpunit-watcher | Full | +| ping | Partial | +| pip | Full | +| pip3 | Partial | +| pipenv | Partial | +| pm2 | Partial | +| pmset | Partial | +| pnpm | Partial | +| pnpx | Partial | +| pod | Partial | +| poetry | Partial | +| pre-commit | Partial | +| preset | Partial | +| prettier | Partial | +| prisma | Partial | +| projj | Partial | +| ps | Partial | +| pscale | Partial | +| psql | Partial | +| publish | Partial | +| pulumi | Partial | +| pushd | Partial | +| pwd | Partial | +| pyenv | Full | +| python | Partial | +| python3 | Partial | +| qodana | Partial | +| quickmail | Partial | +| r | Partial | +| rails | Partial | +| railway | Partial | +| rake | Partial | +| rancher | Partial | +| rbenv | Partial | +| rclone | Partial | +| react-native | Full | +| readlink | Partial | +| redwood | Partial | +| remix | Partial | +| remotion | Partial | +| repeat | Partial | +| rg | Partial | +| rm | Partial | +| rmdir | Partial | +| robot | Partial | +| rollup | Partial | +| rscript | Partial | +| rsync | Partial | +| ruby | Partial | +| rush | Partial | +| rushx | Partial | +| rustc | Partial | +| rustup | Partial | +| sam | Partial | +| scc | Partial | +| scp | Partial | +| screen | Partial | +| sed | Partial | +| sequelize | Partial | +| serve | Partial | +| serverless | Partial | +| sfdx | Partial | +| sftp | Partial | +| shopify | Partial | +| shortcuts | Partial | +| shred | Partial | +| sips | Partial | +| softwareupdate | Partial | +| source | Partial | +| splash | Partial | +| split | Partial | +| spotify | Partial | +| sqlite3 | Partial | +| src | Partial | +| ssh | Full | +| st2 | Partial | +| start-storybook | Partial | +| stat | Partial | +| steadybit | Partial | +| stepzen | Partial | +| stripe | Partial | +| su | Partial | +| subl | Partial | +| sudo | Partial | +| swc | Partial | +| swift | Partial | +| sysctl | Partial | +| tac | Partial | +| tail | Partial | +| tailscale | Partial | +| tailwindcss | Partial | +| tangram | Partial | +| tar | Full | +| task | Partial | +| tccutil | Partial | +| tee | Partial | +| terraform | Full | +| terragrunt | Partial | +| tfenv | Partial | +| tfsec | Partial | +| then | Partial | +| time | Partial | +| tldr | Partial | +| tmux | Full | +| tmuxinator | Full | +| tns | Partial | +| tokei | Partial | +| top | Partial | +| touch | Partial | +| tr | Partial | +| traceroute | Partial | +| trash | Partial | +| trex | Partial | +| trivy | Partial | +| truffle | Partial | +| truncate | Partial | +| trunk | Partial | +| ts-node | Partial | +| tsc | Partial | +| tsh | Partial | +| turbo | Partial | +| twiggy | Partial | +| twilio | Partial | +| typeorm | Partial | +| uname | Partial | +| uniq | Partial | +| until | Partial | +| until | Partial | +| unzip | Partial | +| vale | Partial | +| valet | Partial | +| vapor | Partial | +| vault | Partial | +| vela | Partial | +| vercel | Partial | +| vi | Partial | +| vim | Partial | +| vimr | Partial | +| vite | Partial | +| vite | Partial | +| volta | Partial | +| vr | Partial | +| vsce | Partial | +| vtex | Partial | +| vue | Partial | +| vue | Partial | +| vultr-cli | Partial | +| w | Partial | +| w | Partial | +| wasm-bindgen | Partial | +| wasm-pack | Partial | +| watson | Partial | +| wc | Partial | +| wc | Partial | +| wd | Partial | +| webpack | Partial | +| wget | Partial | +| whence | Partial | +| where | Partial | +| which | Partial | +| while | Partial | +| who | Partial | +| whois | Partial | +| wifi-password | Partial | +| wifi-password | Partial | +| wp | Partial | +| wrangler | Partial | +| wrk | Partial | +| wscat | Partial | +| xargs | Partial | +| xcode-select | Partial | +| xcodebuild | Partial | +| xcodeproj | Partial | +| xcrun | Partial | +| xed | Partial | +| yank | Partial | +| yarn | Partial | +| yo | Partial | +| youtube-dl | Partial | +| z | Partial | +| z | Partial | +| zapier | Partial | +| zapier | Partial | +| zip | Partial | +| zoxide | Partial | diff --git a/src/content/docs/terminal/command-completions/index.mdx b/src/content/docs/terminal/command-completions/index.mdx new file mode 100644 index 0000000..4412d25 --- /dev/null +++ b/src/content/docs/terminal/command-completions/index.mdx @@ -0,0 +1,17 @@ +--- +title: Command Completions +description: >- + Warp's main features for command completions and autosuggestions. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +1. [Completions](/terminal/command-completions/completions/) will suggest commands, option names, and path parameters for you. +2. [Autosuggestions](/terminal/command-completions/autosuggestions/) will automatically suggest commands as you type based on shell history and possible completions. + +## Completions + +<VideoEmbed url="https://www.loom.com/share/92594c821ae341f69d5d1c1af56f2c69?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Completions Demo" /> + +## Autosuggestions + +<VideoEmbed url="https://www.loom.com/share/5e87c52ae855486ab88ffb2f89aeaf73?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Autosuggestion Demo" /> diff --git a/src/content/docs/terminal/command-palette.mdx b/src/content/docs/terminal/command-palette.mdx new file mode 100644 index 0000000..786bb51 --- /dev/null +++ b/src/content/docs/terminal/command-palette.mdx @@ -0,0 +1,40 @@ +--- +title: Command Palette +description: >- + Command Palette is a global search to quickly locate Workflows, Notebooks, + keyboard shortcuts, or other actions within Warp. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +![Command Palette Panel](../../../assets/terminal/command-palette-panel.png) + +## How to access it + +<Tabs> + <TabItem label="macOS"> + You can access the Command Palette with the keyboard shortcut `CMD-P`. + </TabItem> + <TabItem label="Windows"> + You can access the Command Palette with the keyboard shortcut `CTRL-SHIFT-P`. + </TabItem> + <TabItem label="Linux"> + You can access the Command Palette with the keyboard shortcut `CTRL-SHIFT-P`. + </TabItem> +</Tabs> + +## How it works + +* Start typing to search for workflows, notebooks, keyboard shortcuts, actions, toggles, etc. +* Activate a specific filter, by clicking on the filter buttons or prepending your search with the following: + * `workflows:` or `w:` will filter for [Workflows](/knowledge-and-collaboration/warp-drive/workflows/). + * `prompts:` or `p:` will filter for [Prompts](/knowledge-and-collaboration/warp-drive/prompts/). + * `notebook:` or `n:` will filter for [Notebooks](/knowledge-and-collaboration/warp-drive/notebooks/). + * `env_vars:` will filter for [Environment Variables](/knowledge-and-collaboration/warp-drive/environment-variables/). + * `files:` will filter for local files. + * `drive:` will filter for [Warp Drive](/knowledge-and-collaboration/warp-drive/). + * `actions:` will filter for Warp-specific actions like settings and features. + * `sessions:` will filter for active sessions with [Session Navigation](/terminal/sessions/session-navigation/). + * `launch_configs:` will filter for [Launch Configurations](/terminal/sessions/launch-configurations/). + +<VideoEmbed url="https://www.loom.com/share/0e6108b295234637a0bb20cc941976e9?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Command Palette Demo" /> diff --git a/src/content/docs/terminal/comparisons/index.mdx b/src/content/docs/terminal/comparisons/index.mdx new file mode 100644 index 0000000..cb49a40 --- /dev/null +++ b/src/content/docs/terminal/comparisons/index.mdx @@ -0,0 +1,19 @@ +--- +title: Terminal comparisons +description: >- + Compare Warp's performance and terminal feature support against other + popular terminal emulators like iTerm2, Alacritty, and WezTerm. +--- + +Warp is a modern terminal built in Rust with GPU rendering, agent support, and a code-editor-style input. Use this section to see how Warp stacks up against other popular terminals on raw performance and feature coverage. + +## How Warp differs + +* **Open source under AGPL v3** — Warp's client lives at [`warpdotdev/warp`](https://github.com/warpdotdev/warp). You can read the code, build from source, and contribute. See [Contributing to Warp](/support-and-community/community/contributing/) for the flow. +* **Built-in agents** — Warp ships with Warp Agent (powered by Oz) and supports third-party CLI agents like Claude Code, Codex, and Gemini CLI from the same terminal. +* **Modern editing** — Cursor placement, multi-line input, block-based output, and integrated code review work like a text editor instead of a traditional terminal emulator. +* **Cross-platform Rust core** — Warp ships on macOS, Linux, and Windows from a single Rust + GPU-rendered codebase. + +## Benchmarks + +* [Performance benchmarks](/terminal/comparisons/performance/) — VTE and Termbench results comparing Warp against Terminal.app, iTerm2, Alacritty, and WezTerm. diff --git a/src/content/docs/terminal/comparisons/performance.mdx b/src/content/docs/terminal/comparisons/performance.mdx new file mode 100644 index 0000000..6ffc2a0 --- /dev/null +++ b/src/content/docs/terminal/comparisons/performance.mdx @@ -0,0 +1,93 @@ +--- +title: Performance benchmarks +description: >- + This is a short comparison of different terminals and their performance. +--- + +## Terminal apps selected for these benchmarks + +We chose to benchmark Warp against 4 other terminal emulator applications, based on their popularity as well as language and principles. Here is the list of the applications we chose for this comparison together with the explanation as to why we decided to include it in our comparison: + +* Terminal.app - the default terminal app available on the macOS; +* ITerm2 - one of the most popular terminal emulators used by macOS users; +* Alacritty & WezTerm - both of those terminals are written in Rust and are well-known for their speed and overall performance, things that Warp is aiming for. + +### Versions & settings used during the comparison + +| Terminal | Version | Terminal size (cols / rows, window is identical pixel-wise) | +| ------------ | ------------------------------ | ----------------------------------------------------------- | +| Warp | v0.2022.04.01.01.37.stable\_03 | 208 cols / 54 rows | +| Terminal.app | Version 2.11 (440) | 188 cols / 72 rows | +| iTerm2 | Build 3.4.15 | 211 cols / 78 rows | +| Alacritty | alacritty 0.10.1 (2844606) | 286 cols / 102 rows | +| Wezterm | 20220319-142410-0fcdea07 | 243 cols / 80 rows | + +### About benchmarks + +We link the source code of each benchmark used, so you can easily reproduce the tests with other terminal apps. Please, note that those benchmarks are not exhaustive. Comparing terminal emulators with each other is not an easy task - right now we're checking how each of the apps behaves when dealing with lots of input and/or output. + +Ideally, the benchmarks would also cover the latency (time between pressing a key and the character showing on the screen, but also a delay between the user's input and communication with the shell). We may include tests that account for that in the future. + +## VTE benchmark + +Benchmark code can be found [here](https://github.com/alacritty/vtebench) with the specific commit we used in our comparison: `93bcc32b6e0f7560e9b1a5a8b0998c04fbf9b50d`. Results in milliseconds. + +### Average time for each of the benchmark tests + +| | Warp avg (ms) | Terminal.app avg (ms) | iTerm avg | Alacritty avg | WezTerm avg | +| -------------------------------- | ------------- | --------------------- | --------- | ------------- | ----------- | +| dense\_cells | 43.88 | 24.91 | 144.84 | 7.25 | 28.15 | +| scrolling | 30.06 | 283.34 | 1257.57 | 31.75 | 687.77 | +| scrolling\_bottom\_region | 117.34 | 257.23 | 1294.25 | 29.1 | 672.67 | +| scrolling\_bottom\_small\_region | 114.52 | 227.75 | 1251 | 25.98 | 669.93 | +| scrolling\_fullscreen | 37.4 | 307.03 | 1565.17 | 37.36 | 1205 | +| scrolling\_top\_region | 120.63 | 209.29 | 2212.2 | 84.42 | 682.6 | +| scrolling\_top\_small\_region | 114.64 | 205.59 | 1216.33 | 21.91 | 663.44 | +| unicode | 66.47 | 34.45 | 93.01 | 16.78 | 1279.25 | + +![VTEbench average results (logarithmic scale )](../../../../assets/terminal/vtebench_avg.png) + +### P90 of the results + +| | Warp p90 | Terminal.app p90 | iTerm p90 | Alacritty p90 | WezTerm p90 | +| -------------------------------- | -------- | ---------------- | --------- | ------------- | ----------- | +| dense\_cells | 52 | 28 | 189 | 8 | 32 | +| scrolling | 32 | 266.76 | 1336 | 32 | 707 | +| scrolling\_bottom\_region | 170 | 243 | 1398 | 30 | 686 | +| scrolling\_bottom\_small\_region | 167 | 224 | 1331 | 30 | 679 | +| scrolling\_fullscreen | 38 | 327 | 1593 | 41 | 1208 | +| scrolling\_top\_region | 178 | 222 | 2243 | 85 | 686 | +| scrolling\_top\_small\_region | 167 | 222 | 1314 | 30 | 666 | +| unicode | 77 | 39 | 90 | 20 | 3883 | + +![VTEbench p90 results (logarithmic scale )](../../../../assets/terminal/vtebench_p90.png) + +## Termbench + +Benchmark code can be found [here](https://github.com/cmuratori/termbench) with the specific commit we used in our comparison: `82afbc69256b4e22de913f0f02f82e0480f3dac5`. + +Below you'll find results for small and regular test sizes. Note that Terminal.app only participated in the small test. Results in seconds. + +### Small test sizes + +| | Warp small (s) | Terminal.app small (s) | iTerm small (s) | Alacritty small | WezTerm small | +| -------------- | -------------- | ---------------------- | --------------- | --------------- | ------------- | +| ManyLine | 6.7854 | 2.6789 | 8.7057 | 1.2532 | 8.9436 | +| LongLine | 9.0033 | 1.6473 | 9.0849 | 0.8179 | 11.4587 | +| FGPerChar | 1.3716 | 453.9888 | 2.6625 | 0.2788 | 0.6487 | +| FGBGPerChar | 2.8403 | 908.894 | 4.5881 | 0.5931 | 0.7283 | +| overall result | 20.0006 | 1367.209 | 25.0413 | 2.943 | 21.7793 | + +![Termbench small results (logarithmic scale )](../../../../assets/terminal/termbench_small.png) + +### Regular test size + +| | Warp regular (s) | iTerm regular (s) | Alacritty regular (s) | WezTerm regular | +| -------------- | ---------------- | ----------------- | --------------------- | --------------- | +| ManyLine | 113.76 | 132.4975 | 19.8802 | 150.8175 | +| LongLine | 155.0937 | 126.7561 | 12.7859 | 207.3647 | +| FGPerChar | 21.8928 | 39.3352 | 4.2925 | 9.4265 | +| FGBGPerChar | 46.312 | 50.5369 | 8.418 | 13.5142 | +| overall result | 337.0585 | 349.1258 | 45.3767 | 381.1229 | + +![Termbench results (logarithmic scale)](../../../../assets/terminal/termbench_regular.png) diff --git a/src/content/docs/terminal/comparisons/terminal-features.mdx b/src/content/docs/terminal/comparisons/terminal-features.mdx new file mode 100644 index 0000000..de18bfe --- /dev/null +++ b/src/content/docs/terminal/comparisons/terminal-features.mdx @@ -0,0 +1,33 @@ +--- +title: Terminal features +description: >- + Below you'll find a table showcasing different terminal features (such as + text attribution) and information about which one of those are supported in + Warp. +--- + +To make it more transparent & useful, we also show the results for 4 other popular macOS terminal emulators. + +| Feature | Warp | Terminal.app | Iterm | Alacritty | Wezterm | +| --------------------------------------------------------- | ---- | ------------ | ----- | --------- | ------- | +| 24-bit (true color) | YES | NO | YES | YES | YES | +| Bold | YES | YES | YES | YES | YES | +| Dim | NO | YES | YES | YES | YES | +| Italic | NO | YES | YES | YES | YES | +| Underline | YES | YES | YES | YES | YES | +| Underline (alt) | YES | NO | YES | YES | YES | +| Double underline | NO | NO | NO | NO | YES | +| Double underline (alt) | YES | NO | YES | YES | YES | +| Curly underline | NO | NO | YES | NO | YES | +| Colored underline | NO | NO | NO | NO | YES | +| Blink | NO | YES | NO | NO | NO | +| Reverse | YES | YES | YES | YES | YES | +| Invisible (but copy-paste-able) | NO | YES | NO | YES | NO | +| Strikethrough | YES | NO | YES | YES | YES | +| Overline | NO | NO | NO | NO | YES | +| [Magic string](https://en.wikipedia.org/wiki/Unicode#Web) | YES | YES | YES | YES | YES | +| Emojis | YES | YES | YES | YES | YES | +| Right-to-left | NO | YES | NO | NO | NO | +| Sixel graphics | NO | NO | YES | NO | NO | + +Based on the [terminal-testdrive.sh](https://gist.github.com/hellricer/e514d9615d02838244d8de74d0ab18b3). diff --git a/src/content/docs/terminal/editor/alias-expansion.mdx b/src/content/docs/terminal/editor/alias-expansion.mdx new file mode 100644 index 0000000..2490f95 --- /dev/null +++ b/src/content/docs/terminal/editor/alias-expansion.mdx @@ -0,0 +1,42 @@ +--- +title: Alias Expansion +description: >- + Warp will automatically expand your aliases as you type in the input editor. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +## How to use it + +<Tabs> + <TabItem label="macOS"> + When Alias Expansion is enabled, type an alias and then hit `SPACE` will expand the alias. + + To insert a space without expanding an alias, the default keybinding is `OPT-SPACE`. + </TabItem> + <TabItem label="Windows"> + When Alias Expansion is enabled, type an alias and then hit `SPACE` will expand the alias. + + To insert a space without expanding an alias, the default keybinding is `ALT-SPACE`. + </TabItem> + <TabItem label="Linux"> + When Alias Expansion is enabled, type an alias and then hit `SPACE` will expand the alias. + + To insert a space without expanding an alias, the default keybinding is `ALT-SPACE`. + </TabItem> +</Tabs> + +:::note +Aliases will not be expanded when the command in the expanded form is the same as the alias itself. e.g. if you have an alias `ls='ls -G'`, `ls` will not be expanded in the input editor. +::: + +## How to access it + +Alias expansion is disabled by default. There are two ways to toggle this on and off: + +* From Settings: Navigate to **Settings** > **Features** > **Terminal Input** and toggle “Expand aliases as you type”. +* From the [Command Palette](/terminal/command-palette/#windows): Search for the “Enable/disable alias expansion” option and hit `ENTER`. + +## How it works + +<VideoEmbed url="https://www.loom.com/share/2267657c033e482890eea75a8a6c5373?hideEmbedTopBar=true&hide_owner=true&hide_share=true&hide_title=true" title="Alias Expansion Demo" /> diff --git a/src/content/docs/terminal/editor/command-inspector.mdx b/src/content/docs/terminal/editor/command-inspector.mdx new file mode 100644 index 0000000..7f24191 --- /dev/null +++ b/src/content/docs/terminal/editor/command-inspector.mdx @@ -0,0 +1,26 @@ +--- +title: Command Inspector +description: >- + Command Inspector (also known as Command X-Ray) surfaces documentation for + sub-parts of your command, directly in Warp's Input Editor. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +## How to access it + +<Tabs> + <TabItem label="macOS"> + Hover over the part of the command you want to inspect with your mouse or press `CMD-SHIFT-I` to inspect the cursor's current location. + </TabItem> + <TabItem label="Windows"> + Hover over the part of the command you want to inspect with your mouse or press `CTRL-SHIFT-I` to inspect the cursor's current location. + </TabItem> + <TabItem label="Linux"> + Hover over the part of the command you want to inspect with your mouse or press `CTRL-SHIFT-I` to inspect the cursor's current location. + </TabItem> +</Tabs> + +## How it works + +<VideoEmbed url="https://www.loom.com/share/a00259927ada41b2895fd5c4072a3dcc?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Command Inspector Demo" /> diff --git a/src/content/docs/terminal/editor/index.mdx b/src/content/docs/terminal/editor/index.mdx new file mode 100644 index 0000000..5ad16b8 --- /dev/null +++ b/src/content/docs/terminal/editor/index.mdx @@ -0,0 +1,48 @@ +--- +title: Modern Text Editing +description: >- + Unlike other terminals, Warp’s input editor operates out of the box like a + modern IDE and the text editors we’re used to. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +:::note +Text Editor Input also works for [SSH sessions](/terminal/warpify/ssh/). +::: + +### Soft Wrapping + +Warp supports soft wrapping in the input editor. If an autosuggestion goes off-screen, the input editor will be horizontally scrollable to make it visible. Some operations treat soft-wrapped lines like a logical line (`TRIPLE-CLICK`) while other operations treat soft wrapped lines like visible different lines (`UP`/`DOWN`, `SHIFT-UP`/`SHIFT-DOWN`). + +### Copy on Select + +Warp supports copy on select for selectable text within [Blocks](/terminal/blocks/). + +* Toggle this feature **Settings** > **Features** > **Terminal** or search for "Copy on select" in the [Command Palette](/terminal/command-palette/). + +### Autocomplete quotes, parentheses, and brackets + +Warp can automatically complete quotes, brackets, and parentheses like you're used to in IDEs. + +* Toggle this feature **Settings** > **Features** > **Text Editing** or search for "Autocomplete quotes" in the [Command Palette](/terminal/command-palette/). + +## How to use it + +<Tabs> + <TabItem label="macOS"> + <table><thead><tr><th width="317">Keyboard binding</th><th>Shortcut description</th></tr></thead><tbody><tr><td><code>ESCAPE</code></td><td>Closes the input suggestions or history menu</td></tr><tr><td><code>CTRL-L</code></td><td>Clears the terminal</td></tr><tr><td><code>CTRL-H</code></td><td>Backspace</td></tr><tr><td><code>CTRL-C</code></td><td>Clear the entire editor buffer</td></tr><tr><td><code>CTRL-U</code></td><td>Copy and Clear the current line</td></tr><tr><td><code>CMD-SHIFT-K</code></td><td>Clear selected lines</td></tr><tr><td><code>CMD-C</code>, <code>CMD-X</code>, <code>CMD-V</code></td><td>Copy, cut, paste</td></tr><tr><td><code>CTRL-W</code> / <code>OPT-D</code></td><td>Cut the word to the left / right of the cursor</td></tr><tr><td><code>OPT-BACKSPACE</code> / <code>OPT-D</code></td><td>Delete the word to the left / right of the cursor</td></tr><tr><td><code>CTRL-K CMD-DELETE</code></td><td>Delete everything to the right of the cursor</td></tr><tr><td><code>OPT-LEFT</code> / <code>OPT-RIGHT</code></td><td>Move to the beginning of the previous / next word</td></tr><tr><td><code>CTRL-OPT-LEFT</code> / <code>CTRL-OPT-RIGHT</code></td><td>Move backward / forward by one subword</td></tr><tr><td><code>CMD-LEFT</code> <code>CTRL-A</code>/ <code>CTRL-E</code> <code>CMD-DOWN</code> <code>CMD-RIGHT</code></td><td>Move the cursor to the start / end of the line</td></tr><tr><td><code>SHIFT-LEFT</code> / <code>SHIFT-RIGHT</code></td><td>Select the character to the left / right of the cursor</td></tr><tr><td><code>OPT-SHIFT-LEFT</code> / <code>OPT-SHIFT-RIGHT</code></td><td>Select the word to the left / right of the cursor</td></tr><tr><td><code>CMD-SHIFT-LEFT</code> / <code>CMD-SHIFT-RIGHT</code></td><td>Select everything to the left / right of the cursor</td></tr><tr><td><code>SHIFT-UP</code> / <code>SHIFT-UP</code></td><td>Select everything above / below the cursor</td></tr><tr><td><code>CMD-A</code></td><td>Select the entire editor buffer</td></tr><tr><td><code>SHIFT-ENTER</code> <code>CTRL-ENTER</code> <code>OPT-ENTER</code></td><td>Insert newline</td></tr><tr><td><code>CTRL-R</code></td><td>Command Search</td></tr><tr><td><code>CMD-D</code></td><td>Split pane</td></tr></tbody></table> + </TabItem> + <TabItem label="Windows"> + <table><thead><tr><th width="317">Keyboard binding</th><th>Shortcut description</th></tr></thead><tbody><tr><td><code>ESCAPE</code></td><td>Closes the input suggestions or history menu</td></tr><tr><td><code>CTRL-L</code></td><td>Clears the terminal</td></tr><tr><td><code>CTRL-H</code></td><td>Backspace</td></tr><tr><td><code>CTRL-C</code></td><td>Clear the entire editor buffer</td></tr><tr><td><code>CTRL-U</code></td><td>Copy and Clear the current line</td></tr><tr><td><code>CTRL-SHIFT-K</code></td><td>Clear selected lines</td></tr><tr><td><code>CTRL-C</code>, <code>CTRL-X</code>, <code>CTRL-V</code></td><td>Copy, cut, paste</td></tr><tr><td><code>CTRL-W</code> / <code>ALT-D</code></td><td>Cut the word to the left / right of the cursor</td></tr><tr><td><code>ALT-BACKSPACE</code> / <code>ALT-D</code></td><td>Delete the word to the left / right of the cursor</td></tr><tr><td><code>CTRL-K</code></td><td>Delete everything to the right of the cursor</td></tr><tr><td><code>ALT-LEFT</code> / <code>ALT-RIGHT</code></td><td>Move to the beginning of the previous / next word</td></tr><tr><td><code>CTRL-LEFT</code> / <code>CTRL-RIGHT</code></td><td>Move backward / forward by one subword</td></tr><tr><td><code>CTRL-A</code>/ <code>CTRL-E</code></td><td>Move the cursor to the start / end of the line</td></tr><tr><td></td><td>Select the character to the left / right of the cursor</td></tr><tr><td><code>META-SHIFT-B</code> / <code>META-SHIFT-F</code></td><td>Select the word to the left / right of the cursor</td></tr><tr><td></td><td>Select everything to the left / right of the cursor</td></tr><tr><td><code>SHIFT-UP</code> / <code>SHIFT-UP</code></td><td>Select everything above / below the cursor</td></tr><tr><td><code>CTRL-A</code></td><td>Select the entire editor buffer</td></tr><tr><td><code>SHIFT-ENTER</code> <code>CTRL-ENTER</code> <code>ALT-ENTER</code></td><td>Insert newline</td></tr><tr><td><code>CTRL-R</code></td><td>Command Search</td></tr><tr><td><code>CTRL-SHIFT-D</code></td><td>Split pane</td></tr></tbody></table> + </TabItem> + <TabItem label="Linux"> + <table><thead><tr><th width="317">Keyboard binding</th><th>Shortcut description</th></tr></thead><tbody><tr><td><code>ESCAPE</code></td><td>Closes the input suggestions or history menu</td></tr><tr><td><code>CTRL-L</code></td><td>Clears the terminal</td></tr><tr><td><code>CTRL-H</code></td><td>Backspace</td></tr><tr><td><code>CTRL-C</code></td><td>Clear the entire editor buffer</td></tr><tr><td><code>CTRL-U</code></td><td>Copy and Clear the current line</td></tr><tr><td><code>CTRL-SHIFT-K</code></td><td>Clear selected lines</td></tr><tr><td><code>CTRL-C</code>, <code>CTRL-X</code>, <code>CTRL-V</code></td><td>Copy, cut, paste</td></tr><tr><td><code>CTRL-W</code> / <code>ALT-D</code></td><td>Cut the word to the left / right of the cursor</td></tr><tr><td><code>ALT-BACKSPACE</code> / <code>ALT-D</code></td><td>Delete the word to the left / right of the cursor</td></tr><tr><td><code>CTRL-K</code></td><td>Delete everything to the right of the cursor</td></tr><tr><td><code>ALT-LEFT</code> / <code>ALT-RIGHT</code></td><td>Move to the beginning of the previous / next word</td></tr><tr><td><code>CTRL-LEFT</code> / <code>CTRL-RIGHT</code></td><td>Move backward / forward by one subword</td></tr><tr><td><code>CTRL-A</code>/ <code>CTRL-E</code></td><td>Move the cursor to the start / end of the line</td></tr><tr><td></td><td>Select the character to the left / right of the cursor</td></tr><tr><td><code>META-SHIFT-B</code> / <code>META-SHIFT-F</code></td><td>Select the word to the left / right of the cursor</td></tr><tr><td></td><td>Select everything to the left / right of the cursor</td></tr><tr><td><code>SHIFT-UP</code> / <code>SHIFT-UP</code></td><td>Select everything above / below the cursor</td></tr><tr><td><code>CTRL-A</code></td><td>Select the entire editor buffer</td></tr><tr><td><code>SHIFT-ENTER</code> <code>CTRL-ENTER</code> <code>ALT-ENTER</code></td><td>Insert newline</td></tr><tr><td><code>CTRL-R</code></td><td>Command Search</td></tr><tr><td><code>CTRL-SHIFT-D</code></td><td>Split pane</td></tr></tbody></table> + </TabItem> +</Tabs> + +## How it Works + +<VideoEmbed url="https://loom.com/share/1517049fefc34227bf1abaf19cc7e6ea?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Text Editor Input Demo" /> + +![soft wrapping text in Warp input editor](../../../../assets/terminal/soft-wrapping.png) diff --git a/src/content/docs/terminal/editor/syntax-error-highlighting.mdx b/src/content/docs/terminal/editor/syntax-error-highlighting.mdx new file mode 100644 index 0000000..883c88d --- /dev/null +++ b/src/content/docs/terminal/editor/syntax-error-highlighting.mdx @@ -0,0 +1,53 @@ +--- +title: "Syntax & Error Highlighting" +description: >- + Color-code commands and underline errors in real time as you type in Warp's + input editor. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +## What is syntax highlighting + +Warp supports Syntax Highlighting in the [Input Editor.](/terminal/editor/) It colors each part of a command to help differentiate between sub-commands, options/flags, arguments, and variables. + +:::caution +Newly installed apps or newly created aliases will not trigger syntax highlighting until you open a new Warp session (new window, tab, or pane), even if you `source` the RC files in the current session. +::: + +### How to access syntax highlighting + +When Syntax Highlighting is enabled, Warp's [Input Editor](/terminal/editor/) automatically recognizes each part of the command as you type it into the Input Editor, and syntactically highlight them. + +### How to enable/disable syntax highlighting + +Syntax highlighting is enabled by default, to toggle it: + +* Through the [Command Palette](/terminal/command-palette/), search for the "Syntax Highlighting" option and click it (or press enter) to enable/disable. +* Through **Settings** > **Features** > **Terminal Input** , toggle "Syntax highlighting for commands" + +### How syntax highlighting works + +<VideoEmbed url="https://www.loom.com/share/87b15de13ee9407b98a24f1a31835784?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Syntax Highlighting Demo" /> + +## What is error underlining + +Warp highlights errors in commands that are typed within the [Input Editor](/terminal/editor/) e.g. if the binary for the command you've typed does not exist. + +:::caution +Newly installed apps or newly created aliases will trigger error underlining until you open a new Warp session (new window, tab, or pane), even if you `source` the RC files in the current session. +::: + +### How to access error underlining + +When Error Underlining is enabled, Warp automatically underlines any invalid commands with a dashed red underline. + +### How to enable/disable error underlining + +Error underlining is enabled by default, to toggle it: + +* Through the [Command Palette](/terminal/command-palette/), search for the "Syntax Highlighting" option and click it (or press enter) to enable/disable. +* Through **Settings** > **Features** > **Terminal Input** , toggle "Error underlining for commands" + +### How error underlining works + +<VideoEmbed url="https://www.loom.com/share/7721e06ed4aa4e1380abae4f5827ef6f?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Error Underlining Demo" /> diff --git a/src/content/docs/terminal/editor/vim.mdx b/src/content/docs/terminal/editor/vim.mdx new file mode 100644 index 0000000..bc5bf63 --- /dev/null +++ b/src/content/docs/terminal/editor/vim.mdx @@ -0,0 +1,148 @@ +--- +title: Input editor Vim keybindings +description: >- + Use input editor Vim keybindings (also known as Vim mode) to edit commands + quickly in Warp. +--- + +## About Vim keybindings + +The Vi family of programs (including Vim and Neovim) are modal text editors that allow for keyboard-driven text editing. Several shells, including `bash` and `zsh`, implement vi-style keybindings. Warp's input editor was built natively to support more modern text editing experiences, which means it replaces the shell's editor capabilities. Warp has its implementation of Vim keybindings (also known as Vim mode) you can use. + +### How to enable Vim keybindings + +:::note +With `bash` and `zsh`, Warp attempts to detect the shell's keybinding settings. If a shell vi mode is detected, Warp may suggest enabling Vim keybindings (also known as Vim mode). +::: + +To manually toggle Vim keybindings in Warp's input editor: + +* Through the [Command Palette](/terminal/command-palette/), search for "Vim Keybindings". +* Through **Settings** > **Features** > **Text Editing**, toggle "Edit commands with Vim keybindings". + +As in `bash` and `zsh`'s vi mode implementations, the editor starts in insert mode. Pressing `CTRL-C` or `ENTER` clears any pending command state. + +### Customizing Keybindings + +At the moment, Warp only supports default Vim keybindings. + +One exception is the keyboard shortcut for exiting insert mode, which can be rebound under**Settings** > **Keyboard shortcuts** > **Exit Vim Insert Mode**, or through the [Command Palette](/terminal/command-palette/) search for "Exit Vim Insert Mode". + +## Supported Keybindings + +Below is a list of the vim functionality implemented in Warp so far. + +### Movement + +See [Vim docs: motion](https://vimdoc.sourceforge.net/htmldoc/motion.html) for more information. + +#### Basic + +| Command(s) | Description | +| ---------------------------- | --------------------------------------------------- | +| `h`, `j`, `k`, `l` | single-char movement | +| `<space>`, `<backspace>` | single-char movement with line wrap | +| `w`, `W`, `b`, `B`, `e`, `E` | word movement | +| `ge`, `gE` | end of previous word | +| `$` | end of line | +| `0` | beginning of line | +| `^` | first non-whitespace character of line | +| `%` | jump to matching bracket | +| `[`, `]` | prev/next unmatched bracket | +| `_` | beginning of the current line | +| `+` | first non-whitespace character of the next line | +| `-` | first non-whitespace character of the previous line | + +#### Multi-line-related + +| Command(s) | Description | +| ---------- | ----------------------- | +| `gg`, `G` | jump to first/last line | + +### Editing + +| Command(s) | Description | +| ---------- | ----------------------------------------------------------- | +| `r` | replace character under cursor | +| `d`, `D` | delete a range or object | +| `c`, `C` | change a range or object (delete, then go to insert mode) | +| `s`, `S` | substitute (like change, but can only delete at the cursor) | +| `x`, `X` | delete under cursor | +| `y`, `Y` | yank (copy) into the clipboard | +| `p`, `P` | paste from the clipboard | +| `u`, `⌃r` | undo, redo | +| `~` | toggle upper/lowercase under cursor | +| `gu` | lowercase under cursor (`u` in visual mode) | +| `gU` | uppercase under cursor (`U` in visual mode) | +| `J` | join current and following lines | +| `.` | repeat last edit | + +See [Vim docs: editing](https://vimdoc.sourceforge.net/htmldoc/editing.html) for more information. + +#### Text Objects + +| Command(s) | Description | +| ---------------- | ------------------------------------------ | +| `i` | inner (exclude delimiters in text object) | +| `a` | around (include delimiters in text object) | +| `w`, `W` | whitespace-delimited string (word) | +| `"`, `'`, \`\`\` | quote-delimited string | +| `(`, `{`, `[` | parenthesized/bracketed string | + +See [Vim docs: text objects](https://vimdoc.sourceforge.net/htmldoc/motion.html#text-objects) for more information. + +### Search + +#### Character Search + +| Command(s) | Description | +| ------------------ | ------------------------------------------------------ | +| `t`, `T`, `f`, `F` | find next/prev matching character on line | +| `;` | repeat last character search in the same direction | +| `,` | repeat last character search in the opposite direction | + +See [Vim docs: left-right motions](https://vimdoc.sourceforge.net/htmldoc/motion.html#f) for more information. + +#### General Search + +Unlike Vim, general search commands don't search within the buffer. Instead, they open Warp's native command search. + +| Command(s) | Description | +| ------------------ | ------------------------ | +| `/`, `?`, `*`, `#` | open Warp command search | + +### Mode Switching + +| Command(s) | Description | +| ---------- | ----------------------------------------------------------------- | +| `i` | insert text before the cursor | +| `I` | insert text before the first non-whitespace character in the line | +| `a` | append text after the cursor | +| `A` | append text at the end of the line | +| `o` | begin new line below the cursor and insert text | +| `O` | begin new line above the cursor and insert text | +| `v` | visual character mode | +| `V` | visual line mode | + +See [Vim docs: insert](https://vimdoc.sourceforge.net/htmldoc/insert.html#insert) and [Vim docs: visual mode](https://vimdoc.sourceforge.net/htmldoc/visual.html#visual-mode) for more information. + +### Registers + +| Command(s) | Description | +| ---------- | --------------- | +| `"` | register prefix | + +Warp currently supports the following registers: + +| Register name | Description | +| ---------------- | ---------------------------------------------------------------- | +| `a`–`z`, `A`–`Z` | named registers | +| `+` | system clipboard | +| `*` | system clipboard | +| `"` | unnamed register, containing the text of the last delete or yank | + +See [Vim docs: registers](https://vimdoc.sourceforge.net/htmldoc/change.html#registers) for more information. + +## Feedback + +The best way to report bugs and request features is through Warp's [GitHub Issues](https://github.com/warpdotdev/Warp/issues) page. Please note that the issue or request is for Vim Keybindings. diff --git a/src/content/docs/terminal/entry/command-corrections.mdx b/src/content/docs/terminal/entry/command-corrections.mdx new file mode 100644 index 0000000..2fde331 --- /dev/null +++ b/src/content/docs/terminal/entry/command-corrections.mdx @@ -0,0 +1,54 @@ +--- +title: Command Corrections +description: >- + Command Corrections provides auto-correct suggestions on previously run + commands to catch typos and forgotten flags, and fix general console errors. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +## What is it + +This feature was built on top of the open-source project [nvdn/thefuck](https://github.com/nvbn/thefuck). Here are some examples that the Warp team usually finds Command Corrections useful for: + +* Misspelled commands + * `gti checkout myBranchName` -> `git checkout myBranchName` + * `cd ap/sorce/executtor` -> `cd app/source/executor` +* Missing flags + * `git push` -> `git push –set-upstream myBranchName` +* Add permissions + * `./script` -> `chmod +x ./script && ./script` + +## How to access it + +* Command Corrections is enabled by default. You can disable Command Corrections by going to **Settings** > **Features** > **Terminal Input** > toggle “Suggest corrected commands”. +* After an incorrect command is run, a panel with the corrected command suggestion appears above the Input Editor. `CLICK` or press the `RIGHT` arrow to insert the suggestion. + +## How it works + +<VideoEmbed url="https://www.loom.com/share/180e1dc8d1504ec39c00694d9fd71b7c?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Command Corrections Demo" /> + +#### Command correction rules: + +| Command | +| ------------------------------------------------------------- | +| brew | +| cargo | +| cat | +| cd | +| chmod | +| conda | +| cp | +| docker | +| generic (command agnostic, e.g. mis-spelling executable name) | +| git | +| go | +| grep | +| java | +| ls | +| mkdir | +| npm | +| pip | +| python | +| sed | +| sudo | +| yarn | diff --git a/src/content/docs/terminal/entry/command-history.mdx b/src/content/docs/terminal/entry/command-history.mdx new file mode 100644 index 0000000..02de58d --- /dev/null +++ b/src/content/docs/terminal/entry/command-history.mdx @@ -0,0 +1,24 @@ +--- +title: Command History +description: >- + Command History helps you quickly find previously run commands. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +## What is it + +While running, Warp isolates the history of each shell session e.g. if you have two Split Panes open, commands created in one pane do not populate the history of the other. Warp combines the history upon closing. + +Command History also provides rich information like exit code, directory, thread, time to finish running, last run, etc. + +![Command History rich information](../../../../assets/terminal/command-history-rich.png) + +## How to access it + +* Hitting `UP` in the [Input Editor](/terminal/editor/) brings up your history and performs a prefix search based on input. +* Pressing `CTRL-R` opens the [Command Search](/terminal/entry/command-search/) panel and initiates a search of your Command History. To navigate the Command Search panel: + * Start typing and Warp will automatically filter using fuzzy search. Warp bolds matching text when filtering with fuzzy search. + +## How it works + +<VideoEmbed url="https://www.loom.com/share/8119beca8d794b06859c5dea1b1377bb?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Command History Demo" /> diff --git a/src/content/docs/terminal/entry/command-search.mdx b/src/content/docs/terminal/entry/command-search.mdx new file mode 100644 index 0000000..1611568 --- /dev/null +++ b/src/content/docs/terminal/entry/command-search.mdx @@ -0,0 +1,40 @@ +--- +title: Command Search +description: >- + Search command history, Workflows, Prompts, and agent conversations with + fuzzy matching. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +The Command Search panel provides unified search across all your terminal inputs, saved commands, and [Terminal and Agent modes](/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes/) conversation history. Use it to quickly find and reuse commands, workflows, or past agent interactions. + +![Command Search Panel](../../../../assets/terminal/command-search-panel.png) + +:::note +Tailor your Command Search experience by toggling off "Show Global Workflows" in **Settings** > **Features** > **Workflows**. When disabled, your search will exclusively encompass YAML and Warp Drive Workflows. +::: + +## Quick Start + +1. Press `CTRL-R` to open the Command Search Panel +2. Type your search query in the input box +3. Press `ENTER` to input the selected command into Warp's Input Editor + +## Search Filters + +You can filter your search results by prepending your search term with any of the following: + +<table><thead><tr><th width="215.78436279296875">Filter</th><th>Shortcuts</th></tr></thead><tbody><tr><td>Command History</td><td><code>history:</code>, <code>h:</code>, or <code>H-TAB</code></td></tr><tr><td>Prompts</td><td><code>prompts:</code>, <code>p:</code>, or <code>P-TAB</code></td></tr><tr><td><a href="/agent-platform/local-agents/interacting-with-agents/">Agent Mode</a> History</td><td><code>ai_history:</code>, <code>a:</code>, or <code>A-TAB</code></td></tr></tbody></table> + +:::note +When a filter is activated, it will be bolded and italicized in the search panel. +::: + +## Additional Features + +* You can expand the menu horizontally by dragging the right edge +* The panel supports fuzzy search and ranks results by relevance + +## How it works + +<VideoEmbed url="https://www.loom.com/share/21a6f58a33754ee7913edbff6d33d8d1?hideEmbedTopBar=true&hide_owner=true&hide_share=true&hide_title=true" title="Command Search Demo" /> diff --git a/src/content/docs/terminal/entry/index.mdx b/src/content/docs/terminal/entry/index.mdx new file mode 100644 index 0000000..a49419c --- /dev/null +++ b/src/content/docs/terminal/entry/index.mdx @@ -0,0 +1,30 @@ +--- +title: Command Entry +description: >- + Warp's main features for Command Entry, History, Synchronized Inputs, YAML + Workflows and More! +--- +import DemoVideo from '@components/DemoVideo.astro'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +1. [Command Corrections](/terminal/entry/command-corrections/) provides auto-correct suggestions on previously run commands to catch typos, and forgotten flags, and fix general console errors. +2. [Command Search](/terminal/entry/command-search/) is a 3-in-1 panel that allows you to search across Command History, Workflows, Notebooks, and AI Command Search all at once. +3. [Command History](/terminal/entry/command-history/) allows Warp to isolate the history of each shell session to make previously run commands easily accessible. +4. [Synchronized Inputs](/terminal/entry/synchronized-inputs/) allow you to easily run the same command in multiple sessions at the same time. +5. [YAML Workflows](/terminal/entry/yaml-workflows/) are easier to execute and share parameterized and searchable commands within Warp. + +## Command Corrections + +<VideoEmbed url="https://www.loom.com/share/180e1dc8d1504ec39c00694d9fd71b7c?hideEmbedTopBar=true&hide_owner=true&hide_share=true&hide_title=true" title="Command Corrections Demo" /> + +## Command Search + +<VideoEmbed url="https://www.loom.com/share/21a6f58a33754ee7913edbff6d33d8d1?hideEmbedTopBar=true&hide_owner=true&hide_share=true&hide_title=true" title="Command Search Demo" /> + +## Command History + +<VideoEmbed url="https://www.loom.com/share/8119beca8d794b06859c5dea1b1377bb?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Command History Demo" /> + +## YAML Workflows + +<DemoVideo src="/assets/terminal/yaml_workflows_demo.mp4" label="YAML Workflows Demo" /> diff --git a/src/content/docs/terminal/entry/synchronized-inputs.mdx b/src/content/docs/terminal/entry/synchronized-inputs.mdx new file mode 100644 index 0000000..adca454 --- /dev/null +++ b/src/content/docs/terminal/entry/synchronized-inputs.mdx @@ -0,0 +1,53 @@ +--- +title: Synchronized Inputs +description: >- + Type a command once and sync it to multiple panes simultaneously. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +### Synchronized inputs vs. broadcast input + +Synchronized inputs in Warp work similarly to “broadcast input” settings in other terminals, but there are some differences. + +With Warp’s synchronized inputs, whatever command you enter in one session will sync to the other sessions in its entirety. Whereas, "broadcast input" typically allows you to "broadcast" individual keystrokes, which may be more suitable for editing parts of commands. + +## How to access it + +There are three ways to access controls to synchronize inputs: + +* [Command Palette](/terminal/command-palette/) in Warp: Search for “synchronize” +* macOS menus for the Warp app: `Edit > Synchronize Input` + +## How to use it + +<Tabs> + <TabItem label="macOS"> + There are two modes available to scope how input is synchronized and one to stop any synchronization: + + * Synchronize All Panes in All Tabs + * Synchronize All Panes in Current Tab `OPT-CMD-I` + * Stop Synchronizing Any Panes `OPT-CMD-I` + </TabItem> + <TabItem label="Windows"> + There are two modes available to scope how input is synchronized and one to stop any synchronization: + + * Synchronize All Panes in All Tabs + * Synchronize All Panes in Current Tab `CTRL-ALT-I` + * Stop Synchronizing Any Panes `CTRL-ALT-I` + </TabItem> + <TabItem label="Linux"> + There are two modes available to scope how input is synchronized and one to stop any synchronization: + + * Synchronize All Panes in All Tabs + * Synchronize All Panes in Current Tab `CTRL-ALT-I` + * Stop Synchronizing Any Panes `CTRL-ALT-I` + </TabItem> +</Tabs> + +When inputs are synchronized, you can start typing in one input editor and that same input will be entered into all of the input editors for all panes in your current tab or all tabs, depending on the scope you selected. + +If you are working in an alternative editor mode (like vim), synchronized inputs will only apply to all tabs with that same editor type running. + +When you get done, you can select “Stop Synchronizing Any Panes” to end the synchronization. + +## How it works diff --git a/src/content/docs/terminal/entry/yaml-workflows.mdx b/src/content/docs/terminal/entry/yaml-workflows.mdx new file mode 100644 index 0000000..62a7b13 --- /dev/null +++ b/src/content/docs/terminal/entry/yaml-workflows.mdx @@ -0,0 +1,226 @@ +--- +title: YAML Workflows +description: >- + Workflows are an easier way to execute and share commands within Warp. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +:::danger +You can continue to use YAML-based workflows, but we recommend using new [workflows in Warp Drive](/knowledge-and-collaboration/warp-drive/workflows/) instead for a better editing experience. +::: + +## What is it + +Workflows are easily parameterized and searchable by name, description, or command arguments. [Common Workflows](https://github.com/warpdotdev/workflows) sourced by the Warp team and community are readily available within the app. Additionally, you can create and scope Workflows locally or to a Git repository. + +## How to use it + +* Open the [Command Search](/terminal/entry/command-search/) or Workflow Search `CTRL-SHIFT-R` panel to find Workflows. +* Once inside the menu, start typing in the search bar to filter the existing Workflows. (e.g. git, android, npm, etc.) +* When a Workflow is selected with `ENTER`, you can use `SHIFT-TAB` to cycle through the arguments. +* You can also expand the menu horizontally with the mouse by dragging it on the right edge. + +:::note +Tailor your [Command Search](/terminal/entry/command-search/) experience by toggling off "Show Global Workflows" in **Settings** > **Features** > **Workflows**. When disabled, your search will exclusively encompass YAML and Warp Drive Workflows. +::: + +## How it works + +<DemoVideo src="/assets/terminal/yaml_workflows_demo.mp4" label="YAML Workflows Demo" /> + +### How is this different from aliases? + +Workflows solve some major pain points with aliases, specifically the: + +1. need to context switch + 1. leave vim, source dotfiles, or reset shell +2. difficulty with attaching documentation +3. inability to easily search or share +4. inability to easily parameterize + +## Creating custom workflows + +### How to create a workflow with YAML + +You can store local workflows (scoped to your machine) in: + +<Tabs> + <TabItem label="macOS"> + ```bash + $HOME/.warp/workflows/ + ``` + </TabItem> + <TabItem label="Windows"> + ```powershell + $env:APPDATA\warp\Warp\data\workflows\ + ``` + </TabItem> + <TabItem label="Linux"> + ```bash + ${XDG_DATA_HOME:-$HOME/.local/share}/warp-terminal/workflows/ + ``` + </TabItem> +</Tabs> + +Or, you can share them with your team by saving them in `{{path_to_git_repo}}/.warp/workflows/`. Local and repository Workflows can be accessed under the "My Workflows" and "Repository Workflows" tab of the Workflows menu, respectively. + +See the existing Workflow spec within the [Workflows repo](https://github.com/warpdotdev/Workflows/tree/main/specs) for examples. Additionally, we outline the file format below: + +<details> + +<summary><a href="https://github.com/warpdotdev/Workflows/blob/main/FORMAT.md">Workflow File Format</a></summary> + +The Workflow file format is a [yaml](https://yaml.org/) file and must have either a \`.yml \` or \`yaml\` extension. If you're new to YAML and want to learn more, see [Learn YAML in Y minutes](https://learnxinyminutes.com/docs/yaml/). + +--- + +**`name`** + +The name of the Workflow. Required. + +**`command`** + +The command that is executed when the Workflow is selected. Required. + +**`tags`** + +An array of tags that are useful to categorize the Workflow. Optional. + +```yaml +tags: ["git", "GitHub"] +``` + +**`description`** + +The description of the Workflow and what it does. Optional. + +**`source_url`** + +The URL from where the Workflow was originally generated from. This is surfaced in [commands.dev](https://www.commands.dev/) for attribution purposes. Optional. + +**`author`** + +The original author of the Workflow. For example, if this Workflow was generated from StackOverflow, the `author` would be the `author` of the StackOverflow post. This is surfaced in [commands.dev](https://www.commands.dev/) for attribution purposes. Optional. + +**`author_url`** + +The URL of original author of the Workflow. For example, if this Workflow was generated from StackOverflow, the `author_url` would be the StackOverflow author's profile page. This is surfaced in [commands.dev](https://www.commands.dev/) for attribution purposes. Optional. + +**`shells`** + +The list of shells where this Workflow is valid. If not specified, the Workflow is assumed to be valid in all shells. This must be one of `zsh`, `bash`, or `fish`. + +**`arguments`** + +A Workflow can have parameterized arguments to specify pieces of the Workflow that need to be filled in by the user. + +You can specify which part of the Workflow command maps to an argument by surrounding it with two curly braces (`{{<argument>}}`). + +For example the Workflow command: + +```bash +for {{variable}} in {{sequence}}; do + {{command}} +done +``` + +Includes 3 arguments: `variable`, `sequence`, and `command`. + +**`arguments.name`** + +The name of the argument. The argument name is used within the command to specify the ranges of the argument. Required. + +```yaml +name: Example Workflow +command: echo {{string}} +arguments: + - name: string + description: The value to echo +``` + +**`arguments.description`** + +The description of the argument. This is surfaced in both [commands.dev](https://www.commands.dev/) and Warp to help users fill in Workflow arguments. Optional + +**`arguments.default_value`** + +The default value for the argument. If specified, the `default_value` replaces the argument name within the command. Optional + +--- + +</details> + +### Where to save workflows + +Local Workflows are scoped to your machine. Repository Workflows are scoped to a Git repository and can be accessed by anyone who has cloned the repo. + +<Tabs> + <TabItem label="macOS"> + ```bash + # Local Workflow Path + $HOME/.warp/workflows/ + + # Repository Workflow Path + {{path_to_git_repo}}/.warp/workflows + ``` + </TabItem> + <TabItem label="Windows"> + ```powershell + # Local Workflow Path + $env:APPDATA\warp\Warp\data\workflows\ + + # Repository Workflow Path + {{path_to_git_repo}}\.warp\workflows + ``` + </TabItem> + <TabItem label="Linux"> + ```bash + # Local Workflow Path + ${XDG_DATA_HOME:-$HOME/.local/share}/warp-terminal/workflows/ + + # Repository Workflow Path + {{path_to_git_repo}}/.warp/workflows + ``` + </TabItem> +</Tabs> + +#### Local Workflows + +To start, create a Workflow subdirectory within + +<Tabs> + <TabItem label="macOS"> + ```bash + mkdir -p $HOME/.warp/workflows/ + ``` + </TabItem> + <TabItem label="Windows"> + ```powershell + New-Item -Path "$env:APPDATA\warp\Warp\data\workflows\" -ItemType Directory + ``` + </TabItem> + <TabItem label="Linux"> + ```bash + mkdir -p ${XDG_DATA_HOME:-$HOME/.local/share}/warp-terminal/workflows/ + ``` + </TabItem> +</Tabs> + +Add your Workflow’s `.yaml` file to this directory; if the file format is valid Warp should automatically load it into the Workflows menu. + +`cp ~/path/to/my_awesome_workflow.yaml {{path_to_local_workflow_folder}}` + +#### Repository Workflows + +You can add a repository Workflow similarly to how you added a local Workflow. Create a Workflows folder in a repository’s root directory and save your `.yaml` file like so: + +``` +cd {{repository_path}} +mkdir -p .warp/workflows/ +cp ~/path/to/my_awesome_workflow.yaml {{path_to_local_workflow_folder}} +``` + +#### Global Workflows + +You can contribute Workflows that will be made available to other Warp users by forking the [Workflows repo](https://github.com/warpdotdev/workflows/tree/main/specs) and opening a pull request. See the [Contributing](https://github.com/warpdotdev/workflows#contributing) section for more details. diff --git a/src/content/docs/terminal/input/classic-input.mdx b/src/content/docs/terminal/input/classic-input.mdx new file mode 100644 index 0000000..b47e8e5 --- /dev/null +++ b/src/content/docs/terminal/input/classic-input.mdx @@ -0,0 +1,121 @@ +--- +title: Classic Input +description: >- + Classic Input lets you use Warp with an editor that resembles a traditional + terminal, offering full terminal features and Agent Mode support out of the + box. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +Classic Input corresponds to the **Shell (PS1)** option under **Settings** > **Appearance** > **Input**. It provides a traditional terminal experience with support for shell customizations like PS1 prompts, oh-my-zsh themes, same-line prompts, and more. + +Warp's default input uses [Terminal and Agent modes](/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes/), which provide a clean terminal by default and a dedicated conversation view for agent interactions. Classic Input is an alternative for users who prefer a more traditional terminal. + +[Agent Mode](/agent-platform/local-agents/interacting-with-agents/) works in Classic Input with some minor differences from the default input. + +## Features + +Classic Input supports all of Warp's core terminal features, including the following and more: + +* [Prompt](/terminal/appearance/prompt/) — Use a fully customizable Warp prompt or your shell prompt, with support for PS1 and same-line prompts. +* [Input Position](/terminal/appearance/input-position/) — Choose where the input appears in Warp, including both the prompt and the command line. +* [Modern Text Editing](/terminal/editor/) — Warp's input editor works like a modern IDE, with rich editing capabilities not found in most terminals. +* [Command Entry](/terminal/entry/) — Access Warp's features for command history, synchronized inputs, YAML workflows, and more. +* [Text Selection](/terminal/more-features/text-selection/) — Use smart selection or rectangular (column) selection to highlight text precisely without tedious cleanup. + +## How to enter Agent Mode + +You can enter Agent Mode in a few ways: + +<Tabs> + <TabItem label="macOS"> + * Type any natural language, like a task or a question, in the terminal input. Warp will recognize natural language with a local auto-detection feature and prepare to send your query to an Oz agent. + * Use the keyboard shortcut `⌘+I` to toggle into Agent Mode, or type `*+Space`. + * Click the “AI” sparkles icon in the menu bar, and this will open a new terminal pane that starts in Agent Mode. + * From a block you want to ask an Oz agent about, you can click the sparkles icon in the toolbelt, or click on its block context menu item "Attach block(s) to AI query". + </TabItem> + <TabItem label="Windows"> + * Type any natural language, like a task or a question, in the terminal input. Warp will recognize natural language with a local auto-detection feature and prepare to send your query to an Oz agent. + * Use the keyboard shortcut `Ctrl+I` to toggle into Agent Mode, or type `*+Space`. + * Click the "AI" sparkles icon in the menu bar, and this will open a new terminal pane that starts in Agent Mode. + * From a block you want to ask an Oz agent about, you can click the sparkles icon in the toolbelt, or click on its block context menu item "Attach block(s) to AI query". + </TabItem> + <TabItem label="Linux"> + * Type any natural language, like a task or a question, in the terminal input. Warp will recognize natural language with a local auto-detection feature and prepare to send your query to an Oz agent. + * Use the keyboard shortcut `Ctrl+I` to toggle into Agent Mode, or type `*+Space`. + * Click the "AI" sparkles icon in the menu bar, and this will open a new terminal pane that starts in Agent Mode. + * From a block you want to ask an Oz agent about, you can click the sparkles icon in the toolbelt, or click on its block context menu item "Attach block(s) to AI query". + </TabItem> +</Tabs> + +This opens an agent conversation where you can write questions and tasks in an ongoing conversation with Warp's agent. + +When you are in Agent Mode, a ✨ sparkles icon will display in line with your terminal input. + +![The sparkles on the command line indicate Agent Mode is active.](../../../../assets/terminal/undo_my_git_commit.png) + +## Auto-detection for natural language and configurable settings + +The feature Warp uses to detect natural language automatically is completely local. None of your input is sent to AI unless you press `Enter` in Agent Mode. + +If you find that certain shell commands are falsely detected as natural language, you can fix the model by adding those commands to a denylist in **Settings** > **Agents** > **Warp Agent** > **Natural language denylist**. + +You can also turn autodetection off from **Settings** > **Agents** > **Warp Agent** > **Autodetect agent prompts in terminal input**. + +The first time you enter Agent Mode, you will be served a banner with the option to disable auto-detection for natural language on your command line: + +![Warp displays an option to toggle natural language detection on / off](../../../../assets/terminal/banner_for_auto-detection_first_experience.png) + +## Input hints + +Warp input occasionally shows hints within the input editor in a light grey text that helps users learn about features. It's enabled by default. + +* Toggle this feature **Settings** > **Agents** > **Warp Agent** > **Show input hint text** or search for "Input hint text" in the [Command Palette](/terminal/command-palette/) or Right-click on the input editor. + +## How to exit Agent Mode + +<Tabs> + <TabItem label="macOS"> + You can quit Agent Mode at any point with `Esc` or `Ctrl+C`, or toggle out of Agent Mode with `⌘+I`. + </TabItem> + <TabItem label="Windows"> + You can quit Agent Mode at any point with `Esc` or `Ctrl+C`, or toggle out of Agent Mode with `Ctrl+I`. + </TabItem> + <TabItem label="Linux"> + You can quit Agent Mode at any point with `Esc` or `Ctrl+C`, or toggle out of Agent Mode with `Ctrl+I`. + </TabItem> +</Tabs> + +## How to run commands in Agent Mode + +Once you have typed your question or task in the input, press `Enter` to execute your AI query. Agent Mode will send your request to Oz and begin streaming output in the form of an AI block. + +Unlike a chat panel, Agent Mode can complete tasks for you by running commands directly in your session. + +#### Agent Mode command suggestions + +If Agent Mode finds a suitable command that will accomplish your task, it will describe the command in the AI block. It will also fill your terminal input with the suggested command so you can press `Enter` to run the command. + +When you run a command suggested by Agent Mode, that command will work like a standard command you've written in the terminal. No data will be sent back to the AI. + +If the suggested command fails and you want to resolve the error, you can start a new AI query to address the problem. + +![Agent Mode makes a suggestion to run a command.](../../../../assets/terminal/agent-mode-suggestion-1.png) + +#### Agent Mode requested commands + +If Agent Mode doesn't have enough context to assist with a task, it will ask permission to run a command and read the output of that command. + +You must explicitly agree and press `Enter` to run the requested command. When you hit enter, both the command input and the output will be sent to Oz. + +If you do not wish to send the command or its output to AI, you can click Cancel or press `Ctrl+C` to exit Agent Mode and return to the traditional command line. + +![Oz asks permission to run a command and read the output.](../../../../assets/terminal/warp-ai-permissions.png) + +Once a requested command is executed, you can click to expand the output and view command details. + +![Viewing command details](../../../../assets/terminal/warp-ai-viewing-commands.png) + +If a requested command fails, Oz detects it. Agent Mode is self-correcting. It will request another command until it completes the task for you. + +Warp lets you choose from a curated list of LLMs for use in Agent Mode. By default, Warp uses **Auto (Responsive)**, which routes to the highest-quality, fastest available model. You can switch to other supported models — see [Model choice](/agent-platform/capabilities/model-choice/) for the full list. diff --git a/src/content/docs/terminal/input/universal-input.mdx b/src/content/docs/terminal/input/universal-input.mdx new file mode 100644 index 0000000..70ecca0 --- /dev/null +++ b/src/content/docs/terminal/input/universal-input.mdx @@ -0,0 +1,275 @@ +--- +title: Universal Input (Legacy) +description: >- + Universal Input was the previous default input interface for Warp. It has + been replaced by Agent Modality, which provides a cleaner separation between + terminal and agent workflows. +sidebar: + hidden: true +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +:::caution +**This is legacy documentation.** Universal Input has been replaced by [Agent Modality](/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes/), which provides a cleaner terminal experience with a dedicated conversation view for agent interactions. +::: + +The **Universal Input** was the main input interface for using Warp. + +![The Universal Input with an Agent prompt and multiple contextual chips active.](../../../../assets/terminal/universal-input-header.png) + +<VideoEmbed url="https://www.youtube.com/watch?v=4c05OEqzQIA" title="Using the Universal Input" /> + +### Breaking down the Universal Input + +The Universal Input brings together all of Warp's input features into one streamlined editor: + +* **Natural language auto-detection**: Warp can automatically detect when you're writing in plain English, as opposed to a shell command, and switch you into [Agent Mode](/agent-platform/local-agents/interacting-with-agents/#what-is-agent-mode). +* **Contextual chips**: See your current directory, previous conversations, Git status, node version, and more, all inline with your input. +* [**Modern text editing**](/terminal/editor/): Enjoy IDE-like editing features such as [completions](/terminal/command-completions/), [syntax highlighting](/terminal/editor/syntax-error-highlighting/), mouse support, [rectangular selection](/terminal/more-features/text-selection/), and [Next Command](/agent-platform/local-agents/active-ai/) predictions. +* **Input toolbelt**: Quickly access [@-context](/agent-platform/local-agents/agent-context/using-to-add-context/), [Slash Commands](/agent-platform/capabilities/slash-commands/), [voice input](/agent-platform/local-agents/interacting-with-agents/voice/), [image attachments](/agent-platform/local-agents/agent-context/images-as-context/) as context, and other AI features. + +If you prefer a more traditional terminal input experience, you can switch to [Classic Input](/terminal/input/classic-input/) in **Settings** > **Appearance** > **Input**. Classic input also supports oh-my-posh, PS1 customizations, and [same line prompt.](/terminal/appearance/prompt/#same-line-prompt) + +## Input Modes + +The Universal Input supports three modes, shown in the input switcher: + +#### 1. Agent Mode (natural language) + +Ask Warp's agent to build, debug, or run tasks in natural language. Warp uses leading LLMs to interpret your request, run the right commands, surface code diffs, and stream results directly into your session. + +_Indicator:_ Agent icon is highlighted in the switcher. + +![Universal Input locked in Agent Mode.](../../../../assets/terminal/agent-mode-locked-universal-input.png) + +#### 2. Terminal Mode (shell commands) + +Enter shell commands just like any terminal, with the benefit of Warp’s modern editor features—completions, syntax highlighting, error underlining, and more included. + +_Indicator_: Terminal icon highlighted in the switcher + +![Universal Input locked in Terminal Mode.](../../../../assets/terminal/universal-input-terminal-mode.png) + +#### 3. Auto-detection Mode + +Warp automatically detects whether your input is natural language or a shell command. You can stay in detection mode or explicitly lock into Terminal or Agent Mode. + +_Indicator_: Neither mode highlighted. + +![Universal Input in an empty / zero state.](../../../../assets/terminal/zero-state-universal-input.png) + +When Warp detects an input type, the input switcher softly highlights the corresponding mode. + +| Agent (natural language) mode detected | Terminal (shell) mode detected | +| ----------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | +| <img src="../../../../assets/terminal/auto-detection-agent-mode-1.png" alt="Universal Input auto-detecting a natural-language Agent prompt." data-size="original" /> | <img src="../../../../assets/terminal/auto-detection-terminal-mode.png" alt="Universal Input auto-detecting a shell command." data-size="original" /> | + +:::note +The model Warp uses to detect natural language automatically is completely local. +::: + +#### Disabling Natural Language Auto-detection + +By default, auto-detection is enabled. This means Warp decides whether to treat your input as a command or an Agent prompt. + +* **To turn off auto-detection**: go to **Settings** > **AI** > **Input** > **Natural Language Detection** +* When disabled: You’ll explicitly be in either Terminal or Agent Mode. Use the following keyboard shortcuts to switch between modes: + * `CMD+I` (macOS) + * `CTRL+I` (Windows/Linux) + +| Agent (natural language) mode enabled | Terminal (shell) mode enabled | +| -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | +| <img src="../../../../assets/terminal/auto-detection-off-terminal-mode.png" alt="" data-size="original" /> | <img src="../../../../assets/terminal/auto-detection-off-agent-mode.png" alt="" data-size="original" /> | + +### Entering Agent Mode + +[Agent Mode](/agent-platform/local-agents/interacting-with-agents/) is how you interact directly with Warp's AI to ask questions, run tasks, and collaborate in natural language. There are multiple ways to enter Agent Mode depending on where you are in your workflow: + +<Tabs> + <TabItem label="macOS"> + * **Type natural language directly**: If auto-detection is enabled, you can type a task or question into the input, and Warp will recognize it as natural language using its local auto-detection feature. + * **Use keyboard shortcuts**: Quickly toggle into Agent Mode with `CMD + I`. + * **Attach blocks to a prompt**: From any block you want to use as context, click the ✨ icon in the toolbelt or select "Attach block(s)" to AI query from the block’s context menu. + * **Force a mode with special characters**: + * `!` at the start of input forces Terminal Mode. + * `*` at the start of input forces Agent Mode. + * **Switch modes manually**: Click the Agent icon in the input switcher to lock into Agent Mode, or click the terminal icon to switch to Terminal Mode. + </TabItem> + <TabItem label="Windows"> + * **Type natural language directly**: If auto-detection is enabled, you can type a task or question into the input, and Warp will recognize it as natural language using its local auto-detection feature. + * **Use keyboard shortcuts**: Quickly toggle into Agent Mode with `CTRL + I`. + * **Attach blocks to a prompt**: From any block you want to use as context, click the ✨ icon in the toolbelt or select "Attach block(s)" to AI query from the block’s context menu. + * **Force a mode with special characters**: + * `!` at the start of input forces Terminal Mode. + * `*` at the start of input forces Agent Mode. + * **Switch modes manually**: Click the Agent icon in the input switcher to lock into Agent Mode, or click the terminal icon to switch to Terminal Mode. + </TabItem> + <TabItem label="Linux"> + * **Type natural language directly**: If auto-detection is enabled, you can type a task or question into the input, and Warp will recognize it as natural language using its local auto-detection feature. + * **Use keyboard shortcuts**: Quickly toggle into Agent Mode with `CTRL + I`. + * **Attach blocks to a prompt**: From any block you want to use as context, click the ✨ icon in the toolbelt or select "Attach block(s)" to AI query from the block’s context menu. + * **Force a mode with special characters**: + * `!` at the start of input forces Terminal Mode. + * `*` at the start of input forces Agent Mode. + * **Switch modes manually**: Click the Agent icon in the input switcher to lock into Agent Mode, or click the terminal icon to switch to Terminal Mode. + </TabItem> +</Tabs> + +When you're in Agent Mode, the **Agent icon** will be highlighted in the [Universal Input(/terminal/input/universal-input/) + +![The Agent icon in the Universal input indicates that Agent Mode is active.](../../../../assets/terminal/using-agents-universal-input.png) + +In Classic Input, you’ll also see a ✨ sparkles indicator inline. + +![The sparkles on the command line indicate Agent Mode is active.](../../../../assets/terminal/undo_my_git_commit.png) + +By default, entering Agent Mode starts you in _Pair Mode_, where you can continue an ongoing conversation by asking follow-up questions or assigning tasks. From here, you can ask the agent to build, debug, fix, or even deploy code as needed. + +### Exiting Agent or Terminal Modes + +You can leave Agent or Terminal Modes in several ways: + +<Tabs> + <TabItem label="macOS"> + * **Keyboard shortcuts** + * Press `ESC` to quit the current mode. + * Toggle modes with `CMD + I` + * **Force modes with special characters** + * `!` at the start of input forces Terminal Mode. + * `*` at the start of input forces Agent Mode. + * **Manual switching**: click the Agent icon or Terminal icon in the input switcher to swap modes directly. + </TabItem> + <TabItem label="Windows"> + * **Keyboard shortcuts** + * Press `ESC` to quit the current mode. + * Toggle modes with `CTRL + I` + * **Force modes with special characters** + * `!` at the start of input forces Terminal Mode. + * `*` at the start of input forces Agent Mode. + * **Manual switching**: click the Agent icon or Terminal icon in the input switcher to swap modes directly. + </TabItem> + <TabItem label="Linux"> + * **Keyboard shortcuts** + * Press `ESC` to quit the current mode. + * Toggle modes with `CTRL + I` + * **Force modes with special characters** + * `!` at the start of input forces Terminal Mode. + * `*` at the start of input forces Agent Mode. + * **Manual switching**: click the Agent icon or Terminal icon in the input switcher to swap modes directly. + </TabItem> +</Tabs> + +### Natural Language Auto-detection Settings + +Warp can automatically detect when you’re writing in plain English and switch you into Agent Mode. If needed, you can customize or disable this behavior. + +#### Fixing false detections + +If certain shell commands are mistakenly detected as natural language, you can add them to the denylist: **Settings** > **AI** > **Input** > **Natural language denylist** + +#### Turning off auto-detection + +To disable natural language detection entirely, go to: **Settings** > **AI** > **Input Auto-detection** + +When auto-detection is turned off, you’ll need to explicitly switch between Terminal Mode and Agent Mode using `CMD + I` (macOS) or `CTRL + I` (Windows/Linux). + +#### First-time setup + +The first time you enter Agent Mode, Warp will display a banner with the option to disable natural language detection for your command line: + +![Warp displays an option to toggle natural language detection on / off](../../../../assets/terminal/banner_for_auto-detection_first_experience.png) + +--- + +## Contextual Input Chips + +![Universal Input's contextual input chips, from left to right: conversation management, node version, active directory, Git and code diffs, and 2 attached images.](../../../../assets/terminal/universal-input.png) + +The Universal Input includes **contextual chips** that provide inline information about your current environment. These chips surface relevant details such as directory paths, Git status, conversations, or runtime versions, making it easier to navigate, manage context, and take quick actions without leaving the input. + +#### Conversation Management chip + +The conversation management chip shows your recent [Agent conversations](/agent-platform/local-agents/interacting-with-agents/), allowing you to reference or reopen them directly. + +These chips appear in both Agent Mode and Terminal Mode, so you can continue a previous conversation without starting from scratch. For more details, see [Agent Conversations](/agent-platform/local-agents/interacting-with-agents/). + +![The Conversation Management chip displays recent Agent conversations and lets you continue or reopen them directly from the input.](../../../../assets/terminal/conversation-management-chip-universal-input.png) + +These chips appear in both Agent Mode and Terminal Mode, helping you continue a previous conversation without starting from scratch. For more details, refer to [Agent Conversations](/agent-platform/local-agents/interacting-with-agents/). + +#### Active directory chip + +The active directory chip displays your current working directory and enables simple file navigation. Clicking on a folder moves you into that folder, while clicking on a file opens it in [Warp’s native code editor](/code/code-editor/). This makes it possible to move around your workspace seamlessly from within the input. + +![The Active Directory chip lets you browse directories and open files directly from the input.](../../../../assets/terminal/active-directory-chip.png) + +#### Git Status chip + +When you're in a Git-tracked repository, the Git Status chip displays file- and line-level changes. You can switch branches by clicking on the branch name or review modified files in Warp's [native Code Review panel](/code/code-review/). + +The chip updates automatically as files are added, removed, or changed, giving you a real-time view of your repository state. + +![The Git Status chip highlights repository changes and provides quick access to code review.](../../../../assets/terminal/git-branch-chip.png) + +#### File attachments chips + +The file attachments chip lets you attach images and other files directly to a prompt. You can upload up to five [images at a time (as Agent Context)](/agent-platform/local-agents/agent-context/images-as-context/) using the upload button in the toolbelt or by dragging and dropping files into the input. This makes it possible to add screenshots, diagrams, PDFs, or other references directly to your query, giving the Agent richer context. + +![The File Attachments chip allows you to add images or files as context for your queries.](../../../../assets/terminal/images-as-context-chip.png) + +**Node version chip** + +In repositories that include a `package.json`, a Node Version chip appears to show the detected Node.js version. This gives you visibility into your runtime environment without needing to run additional commands. + +![The Node Version chip displays the Node.js version detected in your repository.](../../../../assets/terminal/node-version-chip.png) + +:::note +At this time, contextual chips are not configurable, but they update automatically based on your workspace and repository state. +::: + +--- + +## Input toolbelt + +The **Input Toolbelt** provides quick-access controls alongside the Universal Input. These tools allow you to attach context, run shortcuts, and configure Agent behavior without leaving the input field. Depending on the mode you are in, some features are automatically enabled or will place you into Agent Mode. + +![The Input Toolbelt in Warp’s Universal Input, showing quick-access controls for context, slash commands, voice input, attachments, profiles, and model selection.](../../../../assets/terminal/input-toolbar.png) + +#### @ - Context + +The [@ context chip](/agent-platform/local-agents/agent-context/using-to-add-context/) is available when you are working in a Git repository. Outside of a Git repo, it appears dimmed. + +This feature allows you to attach specific files, folders, code symbols, Warp Drive objects, or blocks from other sessions as context for a prompt. Typing **@** inside the input also opens a context menu where you can search for and select files or directories to include. + +Attaching context with @ works in both Agent Mode (when interacting with Agents) and classic Terminal commands (for referencing file paths). + +**Slash Commands** + +[Slash Commands](/agent-platform/capabilities/slash-commands/) are available in Agent Mode and Auto-detection Modes. They allow you to quickly run built-in actions or saved prompts without leaving the input field. Typing / displays a menu of available commands, which can be customized or extended. + +**Voice Input** + +[Voice Input](/agent-platform/local-agents/interacting-with-agents/voice/) automatically places you in Agent Mode. Speaking directly into Warp lets you phrase tasks, commands, or queries in natural language, and Warp will interpret them as if you had typed them. This feature is especially useful when you want hands-free interaction or when dictating longer tasks. + +**Image Attachments** + +You can [attach images as context](/agent-platform/local-agents/agent-context/images-as-context/) directly to a prompt, which will automatically place you in Agent Mode. This is useful when you want the Agent to reference visual materials such as screenshots, diagrams, or other assets. + +You can add images using the image upload button in the toolbelt (located at the bottom left or right, depending on your input layout). For additional methods of attaching images, see [Images as Context](/agent-platform/local-agents/agent-context/images-as-context/). + +**Fast Forward** + +Fast Forward gives the Agent full autonomy for the remainder of a task or conversation. When enabled, the next prompt you enter allows the Agent to execute commands, read files, and apply code diffs without asking for confirmation each time. This is useful for complex workflows where step-by-step approval would slow things down. + +#### Profile Picker + +The Profile Picker allows you to select from different [Agent Profiles](/agent-platform/capabilities/agent-profiles-permissions/), each with its own configuration of autonomy, tools, and default model. If you have only one profile, the picker will not appear in the UI. + +From the Profile Picker, you can view all available profiles, switch between them, and quickly see the default model attached to each one. Profiles make it possible to tailor Agent behavior for different types of tasks or projects. + +### Model Picker + +The Model Picker is tied to your current Agent Profile. Each profile has a default model, but you can override it at any time using the picker. Warp curates a selection of top large language models (LLMs) for you to choose from, balancing speed, quality, and reasoning ability depending on your needs. + +For a full list of supported models and guidance on when to use them, see [Model Choice](/agent-platform/capabilities/model-choice/). diff --git a/src/content/docs/terminal/integrations-and-plugins.mdx b/src/content/docs/terminal/integrations-and-plugins.mdx new file mode 100644 index 0000000..7373f5c --- /dev/null +++ b/src/content/docs/terminal/integrations-and-plugins.mdx @@ -0,0 +1,89 @@ +--- +title: Terminal Integrations +description: >- + Warp's terminal functionality extends and integrates with popular + development tools. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +## Docker + +:::note +Currently, the Docker extension is only available on macOS. +::: + +[Warp’s Docker extension](https://hub.docker.com/extensions/warpdotdev/warp) makes it more convenient to open Docker containers in Warp. With the extension, you can click to open any Docker container in a [Warpified subshell](/terminal/warpify/subshells/), without manually running `docker exec` or typing out lengthy container IDs. + +Select a container from the list and specify a shell type. Note, that only `bash|zsh|fish` are supported shells for docker containers. Then, select a user (optional) and finally click “Open in Warp” to run commands within the Docker container. + +![Warp's extension for Docker lists available containers](../../../assets/terminal/docker-extension.png) + +## Raycast + +:::note +Currently, the Raycast extension is only available on macOS. +::: + +Warp + Raycast extension helps you open new windows, tabs, or Launch Configurations with [ease](https://twitter.com/warpdotdev/status/1678432353461637121). + +<VideoEmbed url="https://www.raycast.com/warpdotdev/warp" title="Warp + Raycast Extension Link" /> + +:::note +**Terminal Tip**\ +Within `Raycast Settings > Extensions > Apps` search for Warp and assign the alias "terminal" so that it will show up on a search. +::: + +![Raycast Terminal Tip](../../../assets/terminal/raycast-terminal-tip.png) + +## VSCode + +<Tabs> + <TabItem label="macOS"> + Press `SHIFT-CMD-C` while in [VSCode](https://code.visualstudio.com/docs/terminal/basics) to open a new session in Warp. + + <DemoVideo src="/assets/terminal/vscode_new_session.mp4" label="VSCode New Session Shortcut" /> + + To configure this, navigate to Settings in VSCode and search for `Terminal › External: Osx Exec`.\ + \ + Change this to `Warp.app` if you've installed Warp in the default location. Otherwise, put in the full path to the executable. + </TabItem> + <TabItem label="Windows"> + Press `CTRL-SHIFT-C` while in [VSCode](https://code.visualstudio.com/docs/terminal/basics) to open a new session in Warp. + + To configure this, navigate to Settings in VSCode and search for `Terminal › External: Windows Exec`.\ + \ + Change this to `%LOCALAPPDATA%\Programs\Warp\warp.exe` if you've installed Warp in the default location for a single user or `%PROGRAMFILES%\Warp\warp.exe` if you've installed Warp in the default location for all users. Otherwise, put in the full path to the executable. + </TabItem> + <TabItem label="Linux"> + Press `CTRL-SHIFT-C` while in [VSCode](https://code.visualstudio.com/docs/terminal/basics) to open a new session in Warp. + + To configure this, navigate to Settings in VSCode and search for `Terminal › External: Linux Exec`.\ + \ + Change this to `warp-terminal` if you've installed Warp with your distribution's package manager. Otherwise, put in the full path to the executable (e.g. if it is an AppImage). + </TabItem> +</Tabs> + +## JetBrains IDEs + +:::note +Currently, the JetBrains IDE configuration is only available on macOS. +::: + +Press a keyboard shortcut of choice while in a JetBrains IDE to open a new session in Warp. + +To configure this, use the Apple Menu. Click on **Preferences**, go to `External Tools` , and click **Add**. In this menu, put the following information: + +* _Name_: Open Warp +* _Program_: `/Applications/Warp.app` +* _Arguments_: `$ProjectFileDir$` +* _Working Directory_: `/Applications` + +Then press `Ok`. Now you will be able to `Open Warp` from the Apple Menu under `Tools` -> `External Tools`. + +<DemoVideo src="/assets/terminal/jetbrains_external_terminal_config.mp4" label="JetBrains New Session Shortcut" /> + +To attach this configuration to a keyboard shortcut, you must go to the Apple Menu -> `Preferences`. Then go to `Keymap` -> `External Tools`. You will find `Open Warp`. Right-click on it, and select **Add Keyboard Shortcut**. Type your desired shortcut and click save! You're ready to open Warp with a keyboard shortcut. + +<DemoVideo src="/assets/terminal/jetbrains_external_window_keymap_config.mp4" label="JetBrains Configure Keyboard Shortcut" /> diff --git a/src/content/docs/terminal/more-features/accessibility.mdx b/src/content/docs/terminal/more-features/accessibility.mdx new file mode 100644 index 0000000..546dc00 --- /dev/null +++ b/src/content/docs/terminal/more-features/accessibility.mdx @@ -0,0 +1,58 @@ +--- +title: Accessibility +description: >- + Warp's accessibility features include VoiceOver support, voice input, and + configurable verbosity. +--- + +:::note +Note that currently, these instructions are for macOS only. Warp doesn't support screen readers on Linux or Windows and it's being tracked here: [https://github.com/warpdotdev/Warp/issues/3847](https://github.com/warpdotdev/Warp/issues/3847) +::: + +We recognize the need to improve the experience for those visually impaired, as - to our best knowledge - other terminal emulator apps didn't do a good job in this area. This doc summarizes what we've done so far, how Warp works with VoiceOver, and outlines the main changes from the typical workflow. For the features documentation and its keyboard shortcuts, please go to the feature-specific page in the documentation. + +**Keep in mind that this is a work-in-progress and the current state is not a final state of accessibility in Warp**. + +## How to use Warp with Voice Over? + +The best way to start working with Warp & VoiceOver is to install it using Homebrew: + +`brew install warp` + +This will ensure that you can receive all future updates automatically, without the need to go through a macOS standard drag-and-drop installation process. + +From there, Warp should seamlessly work with VoiceOver and start announcing what's happening on the screen and what actions you can take. This may be a major difference from other apps - as Warp announces stuff on its own, letting you know what's going on. There's currently no way to navigate between different UI elements using VO key combinations. + +Once installed, it will ask you to log in. Warp also sends telemetry that we use to improve the overall user experience. You can find out more about that in the [privacy section](/support-and-community/privacy-and-security/privacy/). + +The login flow will require you to navigate between the app and your browser. The last step before you can start enjoying our new terminal app is filling up the onboarding survey. + +The main terminal window is not that different from other terminals - there's a place to type commands (Command Input) and a list of the previously executed commands and their outputs. Warp groups those together - each command and output create a Block. You can navigate blocks with your keyboard to easily check what was the command, learn whether it was successful or not, and what was the output, as well as more easily copy the command, output, or both for further processing. + +A main entry point for discovering new features and actions is our Command Palette, which you can access by executing the cmd-p shortcut. + +## Differences from the regular VoiceOver workflow + +As you may notice, typical Voice Over navigation keys or settings do not currently work in Warp. In short - it's related to how our UI Framework is currently implemented and that as of now we don't yet offer a keyboard-accessible way to navigate the UI elements. + +Instead, whenever you perform an action and/or something happens in the background, Warp announces it to you, letting you know what's going on and what possible actions you can take. Since it's a terminal, we care about all user actions being keyboard accessible from the start, so pretty much all our features have the assigned keybindings already. You can adjust the default keybindings following the guide from this GitHub repository: [https://github.com/warpdotdev/keysets](https://github.com/warpdotdev/keysets). You can also always fall back to using cmd-p to check the keybinding or execute the specific action. + +### A11y specific actions + +Some a11y-specific settings are available through the Command Palette. For example, you can adjust the verbosity level of messages. Simply enter the [Command Palette](/terminal/command-palette/) and type "a11y" to discover related options and their keybindings. + +### Voice Input + +Warp supports voice input as an alternative way to interact with your terminal. This can be especially helpful for users who prefer or require voice commands over typing. You can use voice input to: + +* Issue terminal commands +* Ask questions about command usage +* Perform complex multi-step operations + +Voice input can be enabled in **Settings** > **Agents** > **Warp Agent** > **Voice**. For detailed information about voice features and setup, see our [Voice documentation](/agent-platform/local-agents/interacting-with-agents/voice/). + +## Future work + +While not all Warp features are accessible yet, we've implemented a process around releasing new features and changes to the main app, to ensure that all new code provides proper a11y announcements. + +This is not the ideal and final implementation. We're happy to hear your thoughts and ideas on how we can improve. The biggest milestone for this work is to add support for navigating the UI elements using the keyboard. Give Warp a try, and please, do not hesitate to [share your feedback](/support-and-community/troubleshooting-and-support/sending-us-feedback/). diff --git a/src/content/docs/terminal/more-features/audible-bell.mdx b/src/content/docs/terminal/more-features/audible-bell.mdx new file mode 100644 index 0000000..b77c975 --- /dev/null +++ b/src/content/docs/terminal/more-features/audible-bell.mdx @@ -0,0 +1,11 @@ +--- +title: Audible terminal bell +description: >- + Enable an audible terminal bell in Warp that can be triggered by CLI tools + like ping. +--- + +Warp allows you to enable an audible terminal bell (disabled by default) that can be triggered by a variety of CLI tools (for example, `ping -a`). + +* In Settings, enable an Audible terminal bell in **Settings** > **Features** > **Terminal**. +* In [Command Palette](/terminal/command-palette/), “Enable/Disable Audible Terminal Bell”. diff --git a/src/content/docs/terminal/more-features/files-and-links.mdx b/src/content/docs/terminal/more-features/files-and-links.mdx new file mode 100644 index 0000000..c0d837e --- /dev/null +++ b/src/content/docs/terminal/more-features/files-and-links.mdx @@ -0,0 +1,83 @@ +--- +title: "Files, Links, & Scripts" +description: >- + Quickly open links and files or run scripts with your mouse. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +## Files & Links + +Warp supports opening files, folders, and URL links that are within Blocks. Multiple URL protocols are supported e.g. `https`, `ftp`, `file`, etc. Warp can open files and folders in a variety of editors and opens web links directly in your default browser. Warp can also open markdown files directly with a [Markdown Viewer](/terminal/more-features/markdown-viewer/). + +:::note +Warp also supports iTerm2 and Kitty Image protocols on macOS and Linux. You will need to use a cli tool to view images, in some cases the tools expect `$TERM=kitty`, so you may need to workaround this by setting `TERM=kitty` before the command. We're working on updating the popular tools to recognize Warp natively. +::: + +Warp parses relative and absolute file paths. Warp also tries to capture line and column numbers attached to the file path, supported formats include: + +* `file_name:line_num` +* `file_name:line_num:column_num` +* `file_name[line_num, column_num]` +* `file_name(line_num, column_num)` +* `file_name, line: line_num, column: column_num` +* `file_name, line: line_num, in` + +<Tabs> + <TabItem label="macOS"> + 1. After hovering over a link, open it directly by holding down `CMD` while clicking it. + 2. Clicking a link normally will open a clickable tooltip that says “Open File/Folder/Link”. + 3. Right-clicking a link will open a context menu that supports copying the absolute file path or URL to the clipboard. + </TabItem> + <TabItem label="Windows"> + 1. After hovering over a link, open it directly by holding down `CTRL` while clicking it. + 2. Clicking a link normally will open a clickable tooltip that says “Open File/Folder/Link”. + 3. Right-clicking a link will open a context menu that supports copying the absolute file path or URL to the clipboard. + </TabItem> + <TabItem label="Linux"> + 1. After hovering over a link, open it directly by holding down `CTRL` while clicking it. + 2. Clicking a link normally will open a clickable tooltip that says “Open File/Folder/Link”. + 3. Right-clicking a link will open a context menu that supports copying the absolute file path or URL to the clipboard. + </TabItem> +</Tabs> + +* You can also Drag and drop a folder or file onto the Warp dock icon to open a new tab in this directory. +* You can also right-click on a folder or file in Finder, then select Services, and "Open new Warp Tab | Window here". +* Configure the default editor to open files by navigating to **Settings** > **Features** > **General** > **Choose an editor to open file links**. + * Selecting "Default App" uses your system's default application for the file type. + +#### List of supported editors + +Non exhaustive list of editors, please submit new ones on our GitHub, see [Sending Feedback](/support-and-community/troubleshooting-and-support/sending-us-feedback/#sending-warp-feedback). + +1. `$EDITOR` +2. Visual Studio Code +3. JetBrains IDEs + * WebStorm + * PhpStorm + * GoLand + * PyCharm + * DataGrip + * DataSpell + * Rider + * RubyMine +4. Zed and Zed Preview +5. Cursor +6. Windsurf +7. Sublime Text +8. Android Studio + +<DemoVideo src="/assets/terminal/files-links-demo.mp4" label="Files & Links Demo" /> + +## Scripts + +Warp can open `.command` and Unix Executable files from the finder directly. + +1. Find a `.command` or Shell script you'd like to open in Finder. +2. Right-click and open the script with Warp. + +:::caution +Make sure the file has the appropriate executable permissions before you can run it in Warp. (e.g. `chmod +x script.command`) +::: + +<DemoVideo src="/assets/terminal/script-demo.mp4" label="Scripts Demo" /> diff --git a/src/content/docs/terminal/more-features/full-screen-apps.mdx b/src/content/docs/terminal/more-features/full-screen-apps.mdx new file mode 100644 index 0000000..b8479da --- /dev/null +++ b/src/content/docs/terminal/more-features/full-screen-apps.mdx @@ -0,0 +1,52 @@ +--- +title: Full-screen apps +description: >- + Run Vim, Emacs, and other full-screen apps with configurable mouse reporting + and padding. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +## Mouse and scroll reporting + +Warp supports configuring how to handle mouse and scroll events. They can be sent to the currently running app, e.g. `vim`, or kept and handled by Warp. + +:::note +Mouse reporting must be enabled to also toggle scroll reporting. +::: + +Once mouse reporting is enabled, Warp will use ANSI escape sequences to communicate mouse events to the running app. + +:::note +If you want a mouse event to go to Warp instead (for example, for text selection) without disabling mouse reporting, you can hold the `SHIFT` key. +::: + +### How to access it + +* From the Settings panel, **Settings** > **Features** > **Terminal** > **Enable Mouse Reporting** + * Scroll Reporting can be enabled after toggling **Enable Mouse Reporting** +* From the [Command Palette](/terminal/command-palette/), search for "Toggle Mouse Reporting" +* From the macOS Menu, **View** > **Toggle Mouse Reporting** + +### How it works + +<VideoEmbed url="https://www.loom.com/share/a918696b002148d3beafd545b233c1be?hideEmbedTopBar=true&hide_owner=true&hide_share=true&hide_title=true" title="Mouse and Scroll Reporting Demo" /> + +## Padding + +Warp supports configuring how much padding surrounds full-screen apps. The default is 0 pixel padding, but this can be changed to a custom padding amount or to match the padding in the Blocklist. + +:::note +Warp allows you to scale your terminal by fractions of a cell width | height. When your terminal size is not perfectly aligned to a cell width | height, the extra space appears as padding on the right | bottom. +::: + +### How to access it + +* Go to **Settings** > **Appearance** > **Full-screen Apps** or from the [Command Palette](/terminal/command-palette/) search for "Appearance" + * `Use custom padding in alt-screen` is enabled by default, you can disable it to match the Blocklist padding + * Set the desired uniform padding (px) pixels, which is set to 0px by default + +:::caution +Some full-screen applications don't behave well when resizing. If you are experiencing rendering issues with full screen apps, try turning this setting off. This will ensure that full-screen apps don't need to resize when starting up. +::: + +![alt-screen padding setting](../../../../assets/terminal/padding-settings.png) diff --git a/src/content/docs/terminal/more-features/index.mdx b/src/content/docs/terminal/more-features/index.mdx new file mode 100644 index 0000000..82cb318 --- /dev/null +++ b/src/content/docs/terminal/more-features/index.mdx @@ -0,0 +1,6 @@ +--- +title: More Features +description: >- + Explore additional Warp terminal features beyond the essentials. +--- + diff --git a/src/content/docs/terminal/more-features/linux.mdx b/src/content/docs/terminal/more-features/linux.mdx new file mode 100644 index 0000000..6ef5171 --- /dev/null +++ b/src/content/docs/terminal/more-features/linux.mdx @@ -0,0 +1,17 @@ +--- +title: Warp for Linux +description: >- + Linux-specific features including native Wayland support and crash recovery. +--- + +## Native Wayland + +Warp Wayland support can be enabled in **Settings** > **Features** > **System**. Enabling Wayland support may fix issues with blurry text if you have fractional scaling enabled in your window manager. + +:::caution +When native Wayland is enabled, Global Hotkey support will be disabled. Unlike X11, the Wayland protocol does not expose the configuration necessary to support this feature. +::: + +## Wayland crash recovery + +When Wayland support is enabled, Warp uses a custom crash recovery process to detect any crashes that may occur when using Wayland. If there's a crash, Warp will fallback to use X11 to allow you to continue to use the application. diff --git a/src/content/docs/terminal/more-features/markdown-viewer.mdx b/src/content/docs/terminal/more-features/markdown-viewer.mdx new file mode 100644 index 0000000..d5d7a58 --- /dev/null +++ b/src/content/docs/terminal/more-features/markdown-viewer.mdx @@ -0,0 +1,84 @@ +--- +title: Markdown Viewer +description: >- + Open Markdown files in your terminal and run commands. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +Warp can be used for both editing and viewing rendered Markdown files in a [split pane](/terminal/windows/split-panes/). Any local file with the `.md` or `.markdown` extension is treated as a Markdown file. Remote files are currently not supported. Turning on **Settings** > **Features** > **General** > **Open Markdown files in Warp's Markdown viewer by default** will make the Markdown viewer default, otherwise Markdown files will open in Warp's editor. + +### Opening a file link within a block + +<Tabs> + <TabItem label="macOS"> + For any link to a Markdown file within a block, you can open the file in Warp by `CMD`-clicking on the link, from the link tooltip, or the right-click context menu on the link. + </TabItem> + <TabItem label="Windows"> + For any link to a Markdown file within a block, you can open the file in Warp by `CTRL`-clicking on the link, from the link tooltip, or the right-click context menu on the link. + </TabItem> + <TabItem label="Linux"> + For any link to a Markdown file within a block, you can open the file in Warp by `CTRL`-clicking on the link, from the link tooltip, or the right-click context menu on the link. + </TabItem> +</Tabs> + +![Clicking a Markdown file link in the output of ls to open it in Warp](/assets/terminal/open-markdown-viewer.gif) + +### Markdown-viewing commands + +If you run a Markdown-viewing command like `cat myfile.md`, Warp will show a banner with a button to open the Markdown file. + +The following commands are considered Markdown viewers: + +* `cat` +* `glow` +* `less` + +### Opening a Markdown file from Finder + +From Finder, you can open a Markdown file in Warp from the “Open With” menu that appears when right-clicking on the file. + +### Toggling between editor and viewer + +You can toggle between the Markdown editor and viewer via the pane overflow menu. + +![Clicking a Markdown file link in the output of ls to open it in Warp](/assets/terminal/markdown-raw-rendered-toggle.gif) + +## Shell commands in Markdown files + +Warp can run shell commands from Markdown code blocks in your active terminal session. Click the run icon `>_` to insert a command into the terminal input. + +:::note +The shell command must be in a code block with three backticks ` ``` ` and not inline code for Warp to treat the code like a runnable command. +::: + +Markdown shell blocks also support keyboard navigation. There are two ways to enter the keyboard navigation mode: + +<Tabs> + <TabItem label="macOS"> + * Clicking on a shell block. + * Pressing `CMD-UP` or `CMD-DOWN`. + + Once a shell block is selected, press `CMD-ENTER` to insert it into the terminal input. You can also use `UP`, `DOWN`, `CMD-UP`, and `CMD-DOWN` to navigate between shell blocks. While the Markdown file is focused, press `CMD-L` to switch focus back to the terminal without inserting a command. + </TabItem> + <TabItem label="Windows"> + * Clicking on a shell block. + * Pressing `CTRL-UP` or `CTRL-DOWN`. + + Once a shell block is selected, press `CTRL-ENTER` to insert it into the terminal input. You can also use `UP`, `DOWN`, `CTRL-UP`, and `CTRL-DOWN` to navigate between shell blocks. While the Markdown file is focused, press `CTRL-SHIFT-L` to switch focus back to the terminal without inserting a command. + </TabItem> + <TabItem label="Linux"> + * Clicking on a shell block. + * Pressing `CTRL-UP` or `CTRL-DOWN`. + + Once a shell block is selected, press `CTRL-ENTER` to insert it into the terminal input. You can also use `UP`, `DOWN`, `CTRL-UP`, and `CTRL-DOWN` to navigate between shell blocks. While the Markdown file is focused, press `CTRL-SHIFT-L` to switch focus back to the terminal without inserting a command. + </TabItem> +</Tabs> + +If the command contains any arguments using the curly brace `{{param}}` syntax, they will be treated as Workflow arguments. Learn more about [Workflows](/knowledge-and-collaboration/warp-drive/workflows/). + +<DemoVideo src="/assets/terminal/run-markdown-file-command.mp4" label="Demo of running two commands from a Markdown file in Warp" /> + +In addition, all shell and code blocks have a copy button to quickly copy the block’s text to the clipboard. + +Code blocks without a set language, or one of the following languages, are treated as shell commands: `sh`, `shell`, `bash`, `fish`, `zsh`, `warp-runnable-command`. diff --git a/src/content/docs/terminal/more-features/notifications.mdx b/src/content/docs/terminal/more-features/notifications.mdx new file mode 100644 index 0000000..86a2df2 --- /dev/null +++ b/src/content/docs/terminal/more-features/notifications.mdx @@ -0,0 +1,84 @@ +--- +title: Desktop Notifications +description: >- + Receive desktop notifications when long-running commands complete or need + your input. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +## What is it + +Notifications can be sent when a command completes after a configurable number of seconds or when a running command needs you to enter a password to proceed. For either of these triggers, Warp will only send you a desktop notification if you are using a different app at the time the trigger is fired. + +:::note +For notifications from coding agents (Warp's built-in Agent and third-party CLI agents like Claude Code and OpenCode), see [Agent Notifications](/agent-platform/capabilities/agent-notifications/). +::: + +## Custom notification hooks (OSC 9 / OSC 777) + +Warp supports pluggable notifications triggered by terminal escape sequences, so scripts and tools can raise desktop notifications without additional dependencies. + +- OSC 9 (body only): sends a notification with just a body. + - Format: `ESC ] 9 ; <body> BEL` + - Example (bash/zsh): `printf '\033]9;Build complete\007'` +- OSC 777 (title + body): sends a notification with a title and body. + - Format: `ESC ] 777 ; notify ; <title> ; <body> BEL` + - Example (bash/zsh): `printf '\033]777;notify;Deploy;Success on prod\007'` + +Notes: +- Works on macOS, Windows, and Linux where Warp is allowed to show notifications. +- Newlines and semicolons should be avoided or escaped in payloads. +- This feature is enabled by default in current releases of Warp. + +## How to access it + +### Notifications + +* Notifications are enabled by default and require system permissions to appear. +* If you've turned Notifications off before, toggle it back on by going to **Settings** > **Features** > **Session**, or quickly toggle Notifications with the [Command Palette](/terminal/command-palette/). +* Customize Notification triggers for long-running commands or password prompts by going to **Settings** > **Features** > **Notifications**. + +:::note +On macOS, you will want to **Allow** or **Accept** the request so that Warp can send you desktop notifications. If you accidentally denied it or would like to re-enable Notifications later, check the [troubleshooting guide below](/terminal/more-features/notifications/#troubleshooting-notifications). +::: + +## How it works + +<VideoEmbed url="https://www.loom.com/share/65967f43a7fa432b98cf3e94766a8e79?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Notifications Demo" /> + +## Troubleshooting Notifications + +<Tabs> + <TabItem label="macOS"> + Warp requires two distinct notification settings to work. macOS system settings found in > **System Settings** > **Notifications & Focus** and Warp app settings found in **Settings** > **Features** > **Session** must both be enabled for Notifications to show.\ + \ + If you have Notifications enabled in the system and Warp, but you still aren't receiving desktop notifications, try the following: + + * Make sure that you are navigated away from Warp when you expect to receive the notification. + * Make sure the **Do Not Disturb** mode is turned off in > **System Settings** > **Notifications** > **Notifications & Focus** > **Focus**. + * Go to > **System Settings** > **Notifications & Focus** > **Notifications** and select Warp in the list. Make sure either banner style or alert style notifications are selected, then quit and restart Warp. + * To get the macOS notification prompt to show again for Warp, run `defaults delete dev.warp.Warp-Stable Notifications`, then restart Warp and toggle on the **Settings** > **Features** > **Receive desktop notifications from Warp**. + * Once all of the above is done, please restart macOS to apply the changes and that should help with restoring notifications in Warp. + </TabItem> + <TabItem label="Windows"> + Warp requires two distinct notification settings to work. Windows system settings found in **Settings** > **System** > **Notifications** > **Warp** and Warp app settings found in **Settings** > **Features** > **Session** must both be enabled for Notifications to show. + + If you have Notifications enabled in the system and Warp, but you still aren't receiving desktop notifications, try the following: + + * Make sure that you are navigated away from Warp when you expect to receive the notification. + * Make sure the **Do Not Disturb** mode or **Focus** is turned off. + * Go to **System** > **Notifications** and select Warp in the list. Make sure notifications are turned on, then quit and restart Warp. + </TabItem> + <TabItem label="Linux"> + Warp requires two distinct notification settings to work. Linux system settings found in **Settings** > **Notifications** > **Warp** and Warp app settings found in **Settings** > **Features** > **Session** must both be enabled for Notifications to show. + + If you have Notifications enabled in the system and Warp, but you still aren't receiving desktop notifications, try the following: + + * Make sure that you are navigated away from Warp when you expect to receive the notification. + * Make sure the **Do Not Disturb** mode (if your distribution supports it) is turned off. + * Go to **Settings** > **Notifications** and select Warp in the list. Make sure notifications are turned on, then quit and restart Warp. + </TabItem> +</Tabs> + +Please [reach out to us](/support-and-community/troubleshooting-and-support/sending-us-feedback/#sending-warp-feedback) if you have any other issues. diff --git a/src/content/docs/terminal/more-features/quit-warning.mdx b/src/content/docs/terminal/more-features/quit-warning.mdx new file mode 100644 index 0000000..54d9a07 --- /dev/null +++ b/src/content/docs/terminal/more-features/quit-warning.mdx @@ -0,0 +1,26 @@ +--- +title: Terminal quit warning +description: >- + Warp's quit warning feature is a valuable precaution to prevent + unintentional data loss or lost progress on long-running jobs. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +## What is it + +The quit warning feature ensures that you receive a warning before quitting the app with a running process, allowing you to save your work and avoid any unintended data loss.\ +If you quit the app or close a window containing a session with a running process, you'll see the alert and need to confirm the action before proceeding. If you aren't sure which processes you have running, there is also an option to show those processes. + +## How to access it + +* Open **Settings** > **Features** > **General**, there you can toggle the "Show warning before quitting". +* You can also toggle the quit warning feature in the [Command Palette](/terminal/command-palette/), by searching for \`Quit Warning'. +* If enabled, when you try and close Warp you will see a pop-up window with a few options listed below: + * Yes, quit, which will close all the Warps sessions and running processes. + * Show running processes, which will bring up the [Session Navigation](/terminal/sessions/session-navigation/) panel with a filter for running processes. + * Cancel, which will prevent Warp from closing. + * Don't ask again, which is a box you can check to disable the quit warning feature. + +## How it Works + +<VideoEmbed url="https://www.loom.com/share/bacb9d1c1e3947dca8365e15231cfcd3?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Quit Warning Modal Demo" /> diff --git a/src/content/docs/terminal/more-features/settings-sync.mdx b/src/content/docs/terminal/more-features/settings-sync.mdx new file mode 100644 index 0000000..e3d60c3 --- /dev/null +++ b/src/content/docs/terminal/more-features/settings-sync.mdx @@ -0,0 +1,42 @@ +--- +title: Settings Sync +description: >- + Keep your Warp settings consistent across devices and sessions with + cloud-based sync. +--- + +## How to toggle settings sync + +* You can toggle Settings Sync within the **Settings** > **Account** pane +* Through the [Command Palette](/terminal/command-palette/) by searching for “Settings Sync” + +![Settings Sync in Account pane](../../../../assets/terminal/settings-sync-account.png) + +![Settings Sync in Command Palette](../../../../assets/terminal/settings-sync-palette.png) + +## How settings sync works + +**Settings Sync** works by syncing the state of most of your Warp settings to our cloud servers. + +When you log in to Warp on another device or through the browser with [Session Sharing](/knowledge-and-collaboration/session-sharing/), if you have Settings Sync enabled, most of your settings will be the same as they were when you were logged in before. + +That means your themes, most features, privacy settings, AI settings, **are all the same everywhere you use Warp**, saving you the time from having to set them up again. + +When you first enable Settings Sync, the settings from the computer you enabled it on becomes the default settings for all devices. This is true if you toggle Settings Sync off and on as well - the synced settings are always from **the last device you enabled Settings Sync on**, so toggling effectively causes all of your devices to have settings from the current logged in instance. + +:::note +Read more about privacy for cloud features in the [privacy overview](https://www.warp.dev/privacy/overview). +::: + +### Non-synced settings + +Not all settings are synced, however. Notably, Warp does not sync: + +* Custom keybindings (we may in the future). Although, you can set [custom keybinds with a file](/getting-started/keyboard-shortcuts/#custom-keyboard-shortcuts) +* Custom themes (we may in the future) +* Device specific settings (e.g. what editor you prefer using, startup shell) +* Platform-specific settings are synced across devices on the same platform (e.g. your settings for how to interact with the Linux clipboard are synced across all Linux devices, but not on macOS, Windows, or Web). + +You can tell when a setting is not synced because it will have a special cloud strikethrough icon in the settings panel. + +![Settings not synced](../../../../assets/terminal/settings-not-synced.png) diff --git a/src/content/docs/terminal/more-features/text-selection.mdx b/src/content/docs/terminal/more-features/text-selection.mdx new file mode 100644 index 0000000..34672dd --- /dev/null +++ b/src/content/docs/terminal/more-features/text-selection.mdx @@ -0,0 +1,33 @@ +--- +title: Text selection +description: >- + Use smart selection and rectangular (column) selection to quickly highlight + text in Warp. +--- + +## Smart selection + +**Smart selection** goes beyond the typical double-click selection, which only highlights a single word. Instead, it uses semantic rules to treat common patterns (like URLs or file paths) as one unit, even when separated by punctuation or whitespace. + +![Using smart selection to select a file path by double clicking.](../../../../assets/terminal/smart-selection.png) + +Double-click on text in the input or blocklist. The following patterns are recognized: + +1. URLs +2. File paths +3. Email addresses +4. IP addresses +5. Floating point numbers, including scientific notation. + +You can toggle smart selection on the **Settings** > **Features** > **Terminal** > **Double-click smart selection**. If disabled, you can instead manually select specific punctuation characters to be included within word boundaries. + +## Rectangular selection + +**Rectangular selection** lets you highlight text in a clean vertical block (also called _column_ or _box_ selection). This is especially useful for copying command output, logs, or prefixed text without grabbing unwanted characters. + +![Using rectangular selection to select by columns in the block output.](../../../../assets/terminal/rectangular-selection.png) + +Hold the modifier keys while dragging your mouse: + +* macOS: `CMD-OPT` +* Windows and Linux: `CTRL-ALT` diff --git a/src/content/docs/terminal/more-features/uri-scheme.mdx b/src/content/docs/terminal/more-features/uri-scheme.mdx new file mode 100644 index 0000000..c39aeb9 --- /dev/null +++ b/src/content/docs/terminal/more-features/uri-scheme.mdx @@ -0,0 +1,25 @@ +--- +title: Warp URI Scheme +description: >- + Warps URI scheme enables you to programmatically open new windows, tabs, or + launch configurations with ease. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +## How to use it + +There are several ways to use the URI scheme: + +* Open new window `warp://action/new_window?path=<path_to_folder>` +* Open new tab `warp://action/new_tab?path=<path_to_folder>` +* Open Launch Configuration `warp://launch/<launch_configuration_path>` + +:::note +[Warp Preview](/support-and-community/community/warp-preview-and-alpha-program/) URI scheme begins with `warppreview://` +::: + +## How it works + +Example of Warp [URIs in use in Warp + Raycast Extension](https://github.com/raycast/extensions/blob/74521b70b62355004b0958393a64f9417b1ff3a6/extensions/warp/src/uri.ts). + +<VideoEmbed url="https://twitter.com/i/status/1678432353461637121" title="Warp + Raycast Extension Demo made using URIs" /> diff --git a/src/content/docs/terminal/more-features/working-directory.mdx b/src/content/docs/terminal/more-features/working-directory.mdx new file mode 100644 index 0000000..4835bf5 --- /dev/null +++ b/src/content/docs/terminal/more-features/working-directory.mdx @@ -0,0 +1,25 @@ +--- +title: Working Directory +description: >- + Set a default working directory for new Warp sessions, with options for home + directory, previous session, custom path, or per-window/tab/pane + configuration. +--- +import DemoVideo from '@components/DemoVideo.astro'; + +## What is it + +Warp's working directory feature is designed to enhance your workflow by enabling you to set up a default directory for new sessions. This feature helps you save time and quickly access your preferred directories when starting new sessions. You have the flexibility to set up a working directory for all new sessions or customize it individually for Windows, Tabs, and Panes, based on your specific needs. + +## How to access it + +* Open **Settings** > **Features** > **Session** and go to "Working directory for new sessions". +* The drop-down for this feature provides several options discussed below: + * Home Directory, is the default option for new sessions and opens new sessions in the currently logged-in users home folder `~/`. + * Previous session's directory, opens new sessions in your active sessions' current directory. + * Custom directory, opens new sessions in a file path you specify. + * Advanced, allows you to select from the three options for new sessions in Windows, Tabs, and Panes. + +## How to use it + +<DemoVideo src="/assets/terminal/working-directory-demo.mp4" label="Working Directory Demo" /> diff --git a/src/content/docs/terminal/sessions/index.mdx b/src/content/docs/terminal/sessions/index.mdx new file mode 100644 index 0000000..b0b6d5f --- /dev/null +++ b/src/content/docs/terminal/sessions/index.mdx @@ -0,0 +1,21 @@ +--- +title: Sessions +description: >- + Navigate between sessions and automatically restore windows, tabs, and panes + when you relaunch Warp. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +1. [Session Navigation](/terminal/sessions/session-navigation/) enables you to easily navigate to any session in Warp. +2. [Session Restoration](/terminal/sessions/session-restoration/) automatically restores the window and tabs from your previous session. + +For tab layout configuration, see [Tab Configs](/terminal/windows/tab-configs/) and [Launch Configurations (Legacy)](/terminal/sessions/launch-configurations/) under [Windows and Tabs](/terminal/windows/). + +## Session Navigation + +<VideoEmbed url="https://www.loom.com/share/2147adc6749c4f4ea5da432eadda7995" title="Session Navigation Demo" /> + +## Session Restoration + +<DemoVideo src="/assets/terminal/sessions-block_restoration.mp4" label="Session Restoration Demo" /> diff --git a/src/content/docs/terminal/sessions/launch-configurations.mdx b/src/content/docs/terminal/sessions/launch-configurations.mdx new file mode 100644 index 0000000..53135bf --- /dev/null +++ b/src/content/docs/terminal/sessions/launch-configurations.mdx @@ -0,0 +1,265 @@ +--- +title: Launch Configurations (Legacy) +description: >- + Launch Configurations (Legacy) let you save a configuration of windows, + tabs, and panes. For new setups, use Tab Configs instead. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +:::caution +Launch Configurations have been replaced by [Tab Configs](/terminal/windows/tab-configs/). Existing Launch Configurations continue to work, but new features are not being added. For new setups, use [Tab Configs](/terminal/windows/tab-configs/). +::: + +## What is it + +With Launch configurations you can save in the app or by adding a yaml file. + +## Creating a Launch Configuration + +### From the UI + +1. Set up the configuration of windows, tabs, and panes you would like to save. +2. Open the [Command Palette](/terminal/command-palette/), and type in `Save New Launch Configuration`. +3. Name the configuration file. The name field cannot be empty. +4. Click the Save configuration button. + +### With a YAML File + +* Launch Configurations files are generated when you create them with the UI and can also be created or modified manually. +* Please see the below for [Launch Configuration YAML file locations, format, and examples](/terminal/sessions/launch-configurations/#launch-configuration-yaml-format). + +## Using a Launch Configuration + +<Tabs> + <TabItem label="macOS"> + * From the [Command Palette](/terminal/command-palette/), enter `Launch Configuration` to open and select Launch Configuration. + * Right-clicking the new Tab **+** button to open a menu and select saved Launch Configuration. + * From the macOS menu bar, **File** > **Launch Configurations**, where you can search through and open your saved Launch Configuration. + * Single-window launch configs can be launched into the active window from the launch configuration palette using `CMD-ENTER` on macOS. + </TabItem> + <TabItem label="Windows"> + * From the [Command Palette](/terminal/command-palette/), enter `Launch Configuration` to open and select Launch Configuration. + * Right-clicking the new Tab **+** button to open a menu and select saved Launch Configuration. + * Single-window launch configs can be launched into the active window from the launch configuration palette using `CTRL-ENTER` on Linux. + + To open a WSL tab with a Launch Configuration, you must first set WSL as your default shell in Warp: + + * Go to **Settings** > **Features** > **Session** > **Startup shell for new sessions**. + * Select your desired WSL distribution (e.g., Ubuntu) as the default shell. + + After this, any Launch Configuration you open will use WSL as the shell. + </TabItem> + <TabItem label="Linux"> + * From the [Command Palette](/terminal/command-palette/), enter `Launch Configuration` to open and select Launch Configuration. + * Right-clicking the new Tab **+** button to open a menu and select saved Launch Configuration. + * Single-window launch configs can be launched into the active window from the launch configuration palette using `CTRL-ENTER` on Linux. + </TabItem> +</Tabs> + +:::tip +**Terminal Tip**\ +You can open saved Launch Configurations via Alfred Workflow or [Raycast](/terminal/integrations-and-plugins/#raycast) Extension. Learn more [here](https://blog.joe.codes/open-warp-launch-configurations-from-raycast-and-alfred). Credit to [@joetannenbaum](https://twitter.com/joetannenbaum/status/1633538768866009115) +::: + +## How it works + +<VideoEmbed url="https://www.loom.com/share/daa2a9e55c27458c8bbf722d90078880?hideEmbedTopBar=true&hide_owner=true&hide_share=true&hide_title=true" title="Launch Configuration Demo" /> + +## Launch Configuration YAML Format + +All Launch Configuration yaml files are stored in the following location: + +<Tabs> + <TabItem label="macOS"> + ```bash + $HOME/.warp/launch_configurations/ + ``` + </TabItem> + <TabItem label="Windows"> + ```powershell + $env:APPDATA\warp\Warp\data\launch_configurations\ + ``` + </TabItem> + <TabItem label="Linux"> + ```bash + ${XDG_DATA_HOME:-$HOME/.local/share}/warp-terminal/launch_configurations/ + ``` + </TabItem> +</Tabs> + +:::caution +The `cwd:` value in the yaml code must contain an absolute path or `""`. Note that `~` or empty paths will result in the file not being visible on the list of options for Launch Configurations. +::: + +### Windows + +Sample configuration that shows how windows are structured in launch configuration files. + +```yaml +# Warp Launch Configuration +# +# This configuration has two windows, +# each with one tab in different starting directories. + +--- +name: Example Windows +windows: + - tabs: + - title: Documents + layout: + cwd: /Users/warp-user/Documents + color: blue + - tabs: + - title: Warp User + layout: + cwd: /Users/warp-user + color: green +``` + +### Tabs + +Here's a sample configuration that shows how tabs are structured in launch configuration files. + +* Use the `title` field to set a custom tab name +* Use the `color` field to set the tab color + * We currently support using the terminal colors (ANSI colors): + + `Red | Green | Yellow | Blue | Magenta | Cyan` + + The actual color values will be automatically derived from your Warp theme + +```yaml +# Warp Launch Configuration +# +# This configuration has two tabs in the same window. + +--- +name: Example Tabs +windows: + - tabs: + - title: Documents + layout: + cwd: /Users/warp-user/Documents + color: blue + - title: Warp User + layout: + cwd: /Users/warp-user + color: green +``` + +### Panes + +Launch Configurations support setting split panes in each tab. Note that Warp also supports nesting split panes in launch configuration files. + +```yaml +# Warp Launch Configuration +# +# This configuration is two windows, each with split panes. +# The first window contains a vertically split tab with two panes. +# The second window contains a horizontally split tab, +# with a vertically split tab on the right. + +--- +name: Example Panes +windows: + - tabs: + - title: Downloads and Warp User + layout: + split_direction: vertical + panes: + - cwd: /Users/warp-user/Downloads + - cwd: /Users/warp-user + color: blue + - tabs: + - title: Desktop, Documents, and Warp User + layout: + split_direction: horizontal + panes: + - cwd: /Users/warp-user/Desktop + - split_direction: vertical + panes: + - cwd: /Users/warp-user/Documents + - cwd: /Users/warp-user + color: green +``` + +### Active and Focus + +Sample configuration that shows how a Window and Tab can be activated with a session in focus. + +* Use the `active_window_index` and `active_tab_index`fields to set your active Window and Tab. +* Use the `is_focused` field to set which Pane is focused in each tab. + +:::caution +Note that when you use `- active_tab_index:` the `tabs:` field doesn't need the `-` prefix, as this can cause syntax issues. +::: + +```yaml +# Warp Launch Configuration +# +# This configurations has two tabs, with the second tab active. +# Two vertical split panes in the first tab and the top pane focused. +# Two horizontal split panes in the second tab and the right pane focused. +--- +name: Example Active and Focus +active_window_index: 0 +windows: + - active_tab_index: 1 + tabs: + - title: Tab 1 + layout: + split_direction: vertical + panes: + - cwd: /Users/warp-user/Documents + is_focused: true + - cwd: /Users/warp-user/Documents/Projects + - title: Tab 2 + layout: + split_direction: horizontal + panes: + - cwd: /Users/warp-user/Downloads + - cwd: /Users/warp-user + is_focused: true +``` + +### Commands + +Use the `commands` field to define a set of commands to run when a launch configuration in run. + +:::caution +You may need to use double quotes for commands with special characters. Commands in separate lines are chained together with `&&` when run, as such commands run after `ssh` commands may not execute. +::: + +```yaml +# Warp Launch Configuration +# +# This configuration has two windows, +# the first window executes two commands on start, +# the second window has a split pane that executes a command on start. + +--- +name: Example Commands +windows: + - tabs: + - title: Documents + layout: + cwd: /Users/warp-user/Documents + commands: + - exec: ls + - exec: code . + color: blue + - tabs: + - title: Downloads + layout: + split_direction: vertical + panes: + - cwd: /Users/warp-user/Downloads + commands: + - exec: curl http://example.com -o my.file + - exec: cp my.file my.file2 + - cwd: /Users/warp-user + commands: + - exec: ssh user@remote.server.com + color: green +``` diff --git a/src/content/docs/terminal/sessions/session-navigation.mdx b/src/content/docs/terminal/sessions/session-navigation.mdx new file mode 100644 index 0000000..fe1e8b8 --- /dev/null +++ b/src/content/docs/terminal/sessions/session-navigation.mdx @@ -0,0 +1,25 @@ +--- +title: Session Navigation +description: >- + Quickly navigate to any terminal session across Warp using the Session + Navigation palette. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +## How to access Session navigation + +1. Open the Session Navigation palette with the [Command Palette](/terminal/command-palette/), click on **session >\_** or type in "sessions:". +2. Jump to a session by using your mouse or the `UP ↑`/`DOWN ↓` arrow keys and `ENTER`. +3. Refine the session results by searching for sessions by prompt, the currently running command, last run command, and command status (ex: “Running…”, “Completed 10 minutes ago”, “Empty Session”). + +:::note +Sessions are ordered by recency, so the most recently focused sessions show up first. The Session Navigation palette does not have **PS1** support and can only show Warp's native prompt. +::: + +### CTRL-TAB behavior + +`CTRL-TAB` shortcut defaults to activate the previous / next [Tabs](/terminal/windows/tabs/). You can configure the shortcut to cycle the most recent session, including any [Split Panes](/terminal/windows/split-panes/), in **Settings** > **Features** > **Keys** > **Ctrl-Tab behavior** + +## How session navigation works + +<VideoEmbed url="https://www.loom.com/share/2147adc6749c4f4ea5da432eadda7995" title="Session Navigation Demo" /> diff --git a/src/content/docs/terminal/sessions/session-restoration.mdx b/src/content/docs/terminal/sessions/session-restoration.mdx new file mode 100644 index 0000000..fe37a6e --- /dev/null +++ b/src/content/docs/terminal/sessions/session-restoration.mdx @@ -0,0 +1,93 @@ +--- +title: Session Restoration +description: >- + Restore your windows, tabs, panes, and recent Blocks automatically when you + relaunch Warp. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +## What is it + +Session restoration allows you to quickly pick up where you left off in your previous terminal session. + +## How to access Session Restoration + +* Session Restoration comes enabled by default in Warp. + +:::note +On Linux, opening windows at a specific position is not supported in Wayland. +::: + +* You can disable Session Restoration by going to **Settings** > **Features**, then toggling off `Restore windows, tabs, and panes on startup`. + +:::caution +Toggling off Session Restoration will not clear the [SQLite database](/terminal/sessions/session-restoration/#session-restoration-database); however, Warp will stop recording new output. +::: + +## How session restoration works + +<DemoVideo src="/assets/terminal/sessions-block_restoration.mp4" label="Session Restoration Demo" /> + +#### Session Restoration database + +Warp saves the data from your previous session's windows, tabs, and panes to a SQLite database on your computer, and every time you quit the app, this data is overwritten by your latest session. You can open the database directly and inspect its full contents like so: + +<Tabs> + <TabItem label="macOS"> + ```bash + sqlite3 "$HOME/Library/Group Containers/2BBY89MBSN.dev.warp/Library/Application Support/dev.warp.Warp-Stable/warp.sqlite" + ``` + </TabItem> + <TabItem label="Windows"> + ```powershell + sqlite3 $env:LOCALAPPDATA\warp\Warp\data\warp.sqlite + ``` + </TabItem> + <TabItem label="Linux"> + ```bash + sqlite3 "${XDG_STATE_HOME:-$HOME/.local/state}/warp-terminal/warp.sqlite" + ``` + </TabItem> +</Tabs> + +**How to clear the Session Restoration database** + +Sometimes, you may want to prevent a sensitive Block from being saved on your computer, or you may want to clear blocks from a machine entirely. + +:::note +This interferes with the running session's ability to save content and may require you close Warp before running the database removal commands. +::: + +:::danger +The following guidance is destructive and will delete any sessions and block history. +::: + +There are two ways to do this: + +<Tabs> + <TabItem label="macOS"> + * Clear the blocks from your running Warp session with `CMD-K`. + * Delete the SQLite file entirely with the following command: + + ```bash + rm -f "$HOME/Library/Group Containers/2BBY89MBSN.dev.warp/Library/Application Support/dev.warp.Warp-Stable/warp.sqlite" + ``` + </TabItem> + <TabItem label="Windows"> + * Clear the blocks from your running Warp session with `CTRL-SHIFT-K`. + * Delete the SQLite file entirely with the following command: + + ```powershell + Remove-Item -Force $env:LOCALAPPDATA\warp\Warp\data\warp.sqlite + ``` + </TabItem> + <TabItem label="Linux"> + * Clear the blocks from your running Warp session with `CTRL-SHIFT-K`. + * Delete the SQLite file entirely with the following command: + + ```bash + rm -f "${XDG_STATE_HOME:-$HOME/.local/state}/warp-terminal/warp.sqlite" + ``` + </TabItem> +</Tabs> diff --git a/src/content/docs/terminal/settings/all-settings.mdx b/src/content/docs/terminal/settings/all-settings.mdx new file mode 100644 index 0000000..2939c7c --- /dev/null +++ b/src/content/docs/terminal/settings/all-settings.mdx @@ -0,0 +1,570 @@ +--- +title: All settings reference +description: >- + Complete reference for every setting available in Warp's settings.toml file, + organized by section with descriptions, types, defaults, and examples. +--- + +This page lists every setting you can configure in [`settings.toml`](/terminal/settings/) organized by TOML section. For an introduction to the settings file, how to open it, and common configuration examples, see [Settings file](/terminal/settings/). + +Settings are grouped into sections that correspond to TOML table headers (for example, `[appearance.text]`). Only include the settings you want to change — Warp uses built-in defaults for everything else. + +## General + +Top-level settings that control Warp's startup behavior, session management, and window-level preferences. + +**Section**: `[general]` + +* `default_session_mode` — The default mode for new terminal sessions. Type: string. Default: `"terminal"`. Options: `"terminal"`, `"agent"`, `"cloud_agent"`, `"tab_config"`, `"docker_sandbox"`. +* `default_tab_config_path` — Path to the tab config used when `default_session_mode` is `"tab_config"`. Type: string. Default: `""`. +* `link_tooltip` — Whether to show a tooltip when hovering over links. Type: boolean. Default: `true`. +* `login_item` — Whether to launch Warp automatically when you log in. Type: boolean. Default: `true`. +* `mouse_scroll_multiplier` — The scroll speed multiplier for mouse scroll events. Type: number. Default: `3.0`. +* `new_tab_placement` — Where new tabs are placed in the tab bar. Type: string. Default: `"after_current_tab"`. Options: `"after_current_tab"`, `"after_all_tabs"`. +* `quit_on_last_window_closed` — Whether to quit Warp when the last window is closed. Type: boolean. Default: `false`. +* `restore_session` — Whether to restore the previous session when Warp starts up. Type: boolean. Default: `true`. +* `should_confirm_close_session` — Whether to show a confirmation dialog when closing a session. Type: boolean. Default: `true`. +* `show_changelog_after_update` — Whether the changelog is shown after an update. Type: boolean. Default: `true`. +* `show_warning_before_quitting` — Whether to show a warning dialog before quitting Warp. Type: boolean. Default: `true`. +* `snackbar_enabled` — Whether to show snackbar notifications. Type: boolean. Default: `true`. +* `user_native_preference` — Whether to prefer the native desktop app or the web app. Type: string. Default: `"not_selected"`. Options: `"not_selected"`, `"web"`, `"desktop"`. + +### Undo close + +**Section**: `[general.undo_close]` + +* `enabled` — Whether the undo close feature is enabled. Type: boolean. Default: `true`. +* `grace_period` — How long (in seconds) after closing a tab you can still undo the close. Type: integer. Default: `60`. + +## Appearance + +Visual settings that control how Warp looks, including themes, fonts, cursor, tabs, window, and layout. + +**Section**: `[appearance]` + +* `spacing` — Controls the spacing between terminal blocks. Type: string. Default: `"normal"`. Options: `"normal"`, `"compact"`. + +### Themes + +**Section**: `[appearance.themes]` + +* `theme` — The color theme. Type: string. Default: `"dark"`. Options: `"adeberry"`, `"phenomenon"`, `"dark"`, `"dracula"`, `"fancy_dracula"`, `"cyber_wave"`, `"solar_flare"`, `"solarized_dark"`, `"willow_dream"`, `"light"`, `"dark_city"`, `"gruvbox_dark"`, `"red_rock"`, `"jelly_fish"`, `"leafy"`, `"koi"`, `"solarized_light"`, `"snowy"`, `"gruvbox_light"`, `"pink_city"`, `"marble"`, or a custom theme object. +* `system_theme` — Whether to match the system light/dark theme. Type: boolean. Default: `false`. +* `selected_system_themes` — The themes to use for system light and dark modes. Type: object. Default: `{ dark = "dark", light = "light" }`. + +To use a custom theme: + +```toml +[appearance.themes] +theme = { custom = { name = "My Theme", path = "~/.warp/themes/my-theme.yaml" } } +``` + +### Text + +**Section**: `[appearance.text]` + +* `font_name` — The monospace font used in the terminal. Type: string. Default: `"Hack"`. +* `font_size` — The size of the monospace font in the terminal. Type: number. Default: `13.0`. +* `font_weight` — The weight of the monospace font. Type: string. Default: `"normal"`. Options: `"thin"`, `"extra_light"`, `"light"`, `"normal"`, `"medium"`, `"semibold"`, `"bold"`, `"extra_bold"`, `"black"`. +* `line_height_ratio` — The line height ratio for terminal text. Type: number. Default: `1.2`. +* `ligature_rendering_enabled` — Whether to render font ligatures in the terminal. Type: boolean. Default: `false`. +* `ai_font_name` — The font used for AI-generated content. Type: string. Default: `"Hack"`. +* `match_ai_font` — Whether the AI font automatically matches the terminal font. Type: boolean. Default: `false`. +* `notebook_font_size` — The font size used in notebooks. Type: number. Default: `14.0`. +* `match_notebook_to_monospace_font_size` — Whether the notebook font size matches the terminal font size. Type: boolean. Default: `true`. +* `use_thin_strokes` — Whether to use thin font strokes on macOS. Type: string. Default: `"on_high_dpi_displays"`. Options: `"never"`, `"on_low_dpi_displays"`, `"on_high_dpi_displays"`, `"always"`. +* `enforce_minimum_contrast` — Whether to enforce minimum contrast for text readability. Type: string. Default: `"only_named_colors"`. Options: `"never"`, `"only_named_colors"`, `"always"`. + +### Cursor + +**Section**: `[appearance.cursor]` + +* `cursor_display_type` — The visual style of the cursor. Type: string. Default: `"bar"`. Options: `"bar"`, `"block"`, `"underline"`. +* `cursor_blink` — Whether the cursor blinks. Type: string. Default: `"enabled"`. Options: `"enabled"`, `"disabled"`. + +### Blocks + +**Section**: `[appearance.blocks]` + +* `show_block_dividers` — Whether to show dividers between terminal blocks. Type: boolean. Default: `true`. +* `show_jump_to_bottom_of_block_button` — Whether to show the jump-to-bottom button in long command output. Type: boolean. Default: `true`. +* `should_show_bootstrap_block` — Whether the bootstrap block is visible in the terminal. Type: boolean. Default: `false`. +* `should_show_in_band_command_blocks` — Whether in-band command blocks are visible. Type: boolean. Default: `false`. +* `should_show_ssh_block` — Whether the SSH connection block is visible. Type: boolean. Default: `false`. + +### Tabs + +**Section**: `[appearance.tabs]` + +* `workspace_decoration_visibility` — When workspace decorations such as the tab bar are visible. Type: string. Default: `"hide_fullscreen"`. Options: `"always_show"`, `"hide_fullscreen"`, `"on_hover"`. +* `tab_close_button_position` — Position of the close button on tabs. Type: string. Default: `"right"`. Options: `"right"`, `"left"`. +* `show_indicators_button` — Whether to show activity indicators on tabs. Type: boolean. Default: `true`. +* `preserve_active_tab_color` — Whether to preserve the active tab's color when switching tabs. Type: boolean. Default: `false`. +* `header_toolbar_chip_selection` — Configuration for the header toolbar chips in the vertical tab panel header. Type: string or object. Default: `"default"`. + +### Vertical tabs + +**Section**: `[appearance.vertical_tabs]` + +* `enabled` — Whether to display tabs vertically instead of horizontally. Type: boolean. Default: `false`. +* `view_mode` — Display mode for the vertical tab bar. Type: string. Default: `"compact"`. Options: `"compact"`, `"expanded"`. +* `primary_info` — The primary information displayed on vertical tabs. Type: string. Default: `"command"`. Options: `"command"`, `"working_directory"`, `"branch"`. +* `compact_subtitle` — Subtitle shown on compact vertical tabs. Type: string. Default: `"branch"`. Options: `"branch"`, `"working_directory"`, `"command"`. +* `display_granularity` — Granularity of rows displayed in the vertical tabs panel. Type: string. Default: `"panes"`. Options: `"panes"`, `"tabs"`. +* `tab_item_mode` — Tab item display mode in vertical tabs. Type: string. Default: `"focused_session"`. Options: `"focused_session"`, `"summary"`. +* `show_details_on_hover` — Whether to show a details sidecar when hovering over a vertical tab. Type: boolean. Default: `true`. +* `show_diff_stats` — Whether to show diff stats on vertical tabs. Type: boolean. Default: `true`. +* `show_pr_link` — Whether to show PR links on vertical tabs. Type: boolean. Default: `true`. +* `use_latest_prompt_as_title` — Whether vertical tab names for agent conversations use the latest user prompt. Type: boolean. Default: `false`. + +### Panes + +**Section**: `[appearance.panes]` + +* `focus_pane_on_hover` — Whether panes are focused when hovered over. Type: boolean. Default: `false`. +* `should_dim_inactive_panes` — Whether inactive panes are visually dimmed. Type: boolean. Default: `false`. + +### Input position + +**Section**: `[appearance.input]` + +* `input_mode` — The position of the terminal input. Type: string. Default: `"pinned_to_bottom"`. Options: `"pinned_to_bottom"`, `"pinned_to_top"`, `"waterfall"`. + +### Full-screen apps + +**Section**: `[appearance.full_screen_apps]` + +* `alt_screen_padding` — Controls padding around full-screen terminal applications. Type: string or object. Default: `{ custom = { uniform_padding = 0.0 } }`. + +### Icon + +**Section**: `[appearance.icon]` + +* `app_icon` — The app icon displayed in the dock. Type: string. Default: `"default"`. Options: `"default"`, `"aurora"`, `"classic1"`, `"classic2"`, `"classic3"`, `"comets"`, `"cow"`, `"glass_sky"`, `"glitch"`, `"glow"`, `"holographic"`, `"mono"`, `"neon"`, `"original"`, `"starburst"`, `"sticker"`, `"warp_one"`. + +### Window + +**Section**: `[appearance.window]` + +* `override_opacity` — The opacity of the window background, from 1 to 100 percent. Type: integer. Default: `100`. +* `override_blur` — The blur radius applied to the window background. Type: integer. Default: `1`. +* `override_blur_texture` — Whether to apply a blur texture to the window background. Type: boolean. Default: `false`. +* `zoom_level` — The zoom level for the window, as a percentage. Type: integer. Default: `100`. +* `open_windows_at_custom_size` — Whether to open new windows at a custom size instead of the default. Type: boolean. Default: `false`. +* `new_windows_num_columns` — The number of columns for new windows when using a custom size. Type: integer. Default: `80`. +* `new_windows_num_rows` — The number of rows for new windows when using a custom size. Type: integer. Default: `40`. +* `left_panel_visibility_across_tabs` — Whether the left panel visibility is shared across all tabs. Type: boolean. Default: `true`. + +## Terminal + +Settings that control terminal behavior, input, and event handling. + +**Section**: `[terminal]` + +* `copy_on_select` — Whether text is automatically copied to the clipboard when selected. Type: boolean. Default: `true`. +* `focus_reporting_enabled` — Whether to forward focus and blur events to full-screen terminal applications. Type: boolean. Default: `true`. +* `mouse_reporting_enabled` — Whether to forward mouse events to full-screen terminal applications. Type: boolean. Default: `true`. +* `scroll_reporting_enabled` — Whether to forward scroll events to full-screen terminal applications. Type: boolean. Default: `true`. +* `maximum_grid_size` — The maximum number of rows in the terminal grid. Type: integer. Default: `50000`. +* `use_audible_bell` — Whether to play an audible bell sound on terminal bell events. Type: boolean. Default: `false`. +* `show_terminal_zero_state_block` — Whether to show the AI zero-state block in new terminal sessions. Type: boolean. Default: `true`. + +### Input + +**Section**: `[terminal.input]` + +* `syntax_highlighting` — Whether syntax highlighting is enabled in the terminal input. Type: boolean. Default: `true`. +* `honor_ps1` — Whether to use your shell's PS1 prompt instead of the Warp prompt. Type: boolean. Default: `false`. +* `input_box_type_setting` — The terminal input style. Type: string. Default: `"classic"`. Options: `"universal"` (AI-first input), `"classic"` (Terminal-first input). +* `alias_expansion_enabled` — Whether shell alias expansion is enabled in the input. Type: boolean. Default: `false`. +* `command_corrections` — Whether command corrections are suggested for mistyped commands. Type: boolean. Default: `true`. +* `error_underlining_enabled` — Whether command errors are underlined in the input. Type: boolean. Default: `true`. +* `completions_open_while_typing` — Whether the completions menu opens automatically while typing. Type: boolean. Default: `false`. +* `classic_completions_mode` — Whether classic completions mode is enabled. Type: boolean. Default: `false`. +* `show_hint_text` — Whether hint text is shown in the terminal input. Type: boolean. Default: `true`. +* `show_terminal_input_message_bar` — Whether the terminal input message bar is shown. Type: boolean. Default: `true`. +* `enable_slash_commands_in_terminal` — Whether slash commands are available in the terminal input. Type: boolean. Default: `true`. +* `at_context_menu_in_terminal_mode` — Whether the @ context menu is available in terminal mode. Type: boolean. Default: `true`. +* `outline_codebase_symbols_for_at_context_menu` — Whether codebase symbols appear in the @ context menu. Type: boolean. Default: `true`. +* `middle_click_paste_enabled` — Whether middle-click pastes from the clipboard. Type: boolean. Default: `true`. +* `extra_meta_keys` — Controls which additional keys are treated as meta keys. Type: object. Default: `{ left_alt = false, right_alt = false }`. + +#### Autosuggestions + +**Section**: `[terminal.input.autosuggestions]` + +* `enabled` — Whether command autosuggestions are shown. Type: boolean. Default: `true`. +* `keybinding_hint` — Whether autosuggestion keybinding hints are displayed. Type: boolean. Default: `true`. +* `show_ignore_button` — Whether the ignore button is shown for autosuggestions. Type: boolean. Default: `false`. + +### Smart select + +**Section**: `[terminal.smart_select]` + +* `enabled` — Whether double-click smart selection is enabled for URLs, emails, file paths, and identifiers. Type: boolean. Default: `true`. +* `word_char_allowlist` — Characters considered part of a word for double-click selection when smart select is disabled. Type: string. Default: `"-.~/\"`. + +## Session + +Settings that control shell selection and working directory behavior for new sessions. + +**Section**: `[session]` + +* `startup_shell_override` — The shell to use when Warp starts up. Type: string or null. Default: `null` (uses system default). +* `new_session_shell_override` — The shell to use when opening a new session. Type: string, object, or null. Default: `null` (uses system default). Options: `"system_default"`, `{ executable = "/path/to/shell" }`, `{ custom = "command" }`. + +### Working directory config + +**Section**: `[session.working_directory_config]` + +* `advanced_mode` — Whether to use separate settings per session source. Type: boolean. Default: `false`. + +When `advanced_mode` is `false`, the `[session.working_directory_config.global]` table applies to all session sources. When `true`, you can configure each source independently. + +**Section**: `[session.working_directory_config.global]` (also `.split_pane`, `.new_tab`, `.new_window`) + +* `mode` — How the working directory is determined. Type: string. Default: `"previous_dir"`. Options: `"home_dir"`, `"previous_dir"`, `"custom_dir"`. +* `custom_dir` — Custom directory path, used when mode is `"custom_dir"`. Type: string. Default: `""`. + +```toml +# Use a specific directory for split panes, previous directory for everything else +[session.working_directory_config] +advanced_mode = true + +[session.working_directory_config.global] +mode = "previous_dir" +custom_dir = "" + +[session.working_directory_config.split_pane] +mode = "custom_dir" +custom_dir = "~/projects" + +[session.working_directory_config.new_tab] +mode = "previous_dir" +custom_dir = "" + +[session.working_directory_config.new_window] +mode = "home_dir" +custom_dir = "" +``` + +## Agents + +Settings for Warp's agents, including model behavior, permissions, knowledge, MCP servers, and voice input. + +**Section**: `[agents]` + +* `cloud_conversation_storage_enabled` — Whether conversations are stored in the cloud. Type: boolean. Default: `true`. + +### Knowledge + +**Section**: `[agents.knowledge]` + +* `rules_enabled` — Whether the agent uses your saved rules during requests. Type: boolean. Default: `true`. +* `warp_drive_context_enabled` — Whether Warp Drive context is included in AI requests. Type: boolean. Default: `true`. + +### MCP servers + +**Section**: `[agents.mcp_servers]` + +* `file_based_mcp_enabled` — Whether third-party file-based MCP servers are automatically detected. Type: boolean. Default: `false`. + +### Profiles (permissions) + +**Section**: `[agents.profiles]` + +* `agent_mode_coding_permissions` — The file read permission level for the agent. Type: string. Default: `"always_ask_before_reading"`. Options: `"always_ask_before_reading"`, `"always_allow_reading"`, `"allow_reading_specific_files"`. +* `agent_mode_coding_file_read_allowlist` — File paths the agent can read without asking for permission. Type: array of strings. Default: `[]`. +* `agent_mode_execute_readonly_commands` — Whether the agent can auto-execute read-only commands without asking. Type: boolean. Default: `false`. +* `agent_mode_command_execution_allowlist` — Commands the agent can execute without explicit permission (regex patterns). Type: array of strings. Default: `["cat(\\s.*)?", "echo(\\s.*)?", "find .*", "grep(\\s.*)?", "ls(\\s.*)?", "which .*"]`. +* `agent_mode_command_execution_denylist` — Commands the agent must always ask before executing (regex patterns). Type: array of strings. Default: `["bash(\\s.*)?", "fish(\\s.*)?", "pwsh(\\s.*)?", "sh(\\s.*)?", "zsh(\\s.*)?", "curl(\\s.*)?", "eval(\\s.*)?", "exec(\\s.*)?", "source(\\s.*)?", "wget(\\s.*)?", "dig(\\s.*)?", "nslookup(\\s.*)?", "host(\\s.*)?", "ssh(\\s.*)?", "scp(\\s.*)?", "rsync(\\s.*)?", "telnet(\\s.*)?", "rm(\\s.*)?"]`. + +### Warp Agent (AI features) + +**Section**: `[agents.warp_agent]` + +* `is_any_ai_enabled` — Controls whether all AI features are enabled. Type: boolean. Default: `true`. + +#### Active AI + +**Section**: `[agents.warp_agent.active_ai]` + +* `enabled` — Controls whether proactive AI features like suggestions are enabled. Type: boolean. Default: `true`. +* `code_suggestions_enabled` — Controls whether AI code suggestions are enabled. Type: boolean. Default: `true`. +* `intelligent_autosuggestions_enabled` — Controls whether AI-powered intelligent autosuggestions are enabled. Type: boolean. Default: `true`. +* `agent_mode_query_suggestions_enabled` — Controls whether prompt suggestions are shown in Agent Mode. Type: boolean. Default: `true`. +* `shared_block_title_generation_enabled` — Controls whether titles are auto-generated when sharing blocks. Type: boolean. Default: `true`. + +#### Input + +**Section**: `[agents.warp_agent.input]` + +* `ai_auto_detection_enabled` — Controls whether AI automatically detects natural language input. Type: boolean. Default: `true`. +* `ai_command_denylist` — Commands to exclude from AI natural language autodetection. Type: string. Default: `""`. +* `nld_in_terminal_enabled` — Controls whether natural language detection is enabled in the terminal input. Type: boolean. Default: `false`. +* `show_model_selectors_in_prompt` — Whether to show AI model selectors in the input prompt. Type: boolean. Default: `true`. +* `show_agent_tips` — Whether agent tips are displayed in the input. Type: boolean. Default: `true`. +* `include_agent_commands_in_history` — Whether agent-executed commands are included in command history. Type: boolean. Default: `false`. +* `agent_toolbar_chip_selection_setting` — Controls the layout of context chips in the Agent Mode toolbar. Type: string or object. Default: `"default"`. + +#### Other + +**Section**: `[agents.warp_agent.other]` + +* `thinking_display_mode` — Controls how agent thinking traces are displayed after streaming. Type: string. Default: `"show_and_collapse"`. Options: `"show_and_collapse"`, `"always_show"`, `"never_show"`. +* `open_conversation_layout_preference` — Whether to open agent conversations in a new tab or a split pane. Type: string. Default: `"new_tab"`. Options: `"new_tab"`, `"split_pane"`. +* `show_conversation_history` — Whether conversation history appears in the tools panel. Type: boolean. Default: `true`. +* `show_agent_notifications` — Whether agent notifications are shown. Type: boolean. Default: `true`. +* `should_show_oz_updates_in_zero_state` — Whether the "What's new" section is shown in the agent view. Type: boolean. Default: `true`. +* `should_render_use_agent_toolbar_for_user_commands` — Whether to show the "Use Agent" footer for terminal commands. Type: boolean. Default: `true`. +* `cloud_agent_computer_use_enabled` — Whether computer use is enabled for cloud agent conversations. Type: boolean. Default: `false`. + +### Code review autogeneration + +Controls AI-driven autogeneration in the code review dialogs. This setting currently lives under `[agents.oz.active_ai]` rather than alongside the other `[agents.warp_agent.active_ai]` settings. + +**Section**: `[agents.oz.active_ai]` + +* `git_operations_autogen_enabled` — Controls whether AI auto-generates commit messages and PR title and body in the code review dialogs. Type: boolean. Default: `true`. + +### Third-party (CLI agents) + +**Section**: `[agents.third_party]` + +* `should_render_cli_agent_toolbar` — Whether to show the CLI agent footer for coding agent commands. Type: boolean. Default: `true`. +* `auto_toggle_composer` — Whether CLI agent Rich Input automatically closes and reopens based on the agent's blocked state. Type: boolean. Default: `true`. +* `auto_open_composer_on_cli_agent_start` — Whether CLI agent Rich Input automatically opens when a CLI agent session starts. Type: boolean. Default: `false`. +* `auto_dismiss_composer_after_submit` — Whether CLI agent Rich Input automatically closes after the user submits a prompt. Type: boolean. Default: `false`. +* `cli_agent_toolbar_chip_selection_setting` — Controls the layout of context chips in the CLI Agent toolbar. Type: string or object. Default: `"default"`. +* `cli_agent_toolbar_enabled_commands` — Maps custom toolbar command patterns to specific CLI agents. Type: object. Default: `{}`. + +### Voice + +**Section**: `[agents.voice]` + +* `voice_input_enabled` — Controls whether voice input is enabled for AI interactions. Type: boolean. Default: `true`. +* `voice_input_toggle_key` — The key used to toggle voice input. Type: string. Default: `"none"`. Options: `"none"`, `"fn"`, `"alt_left"`, `"alt_right"`, `"control_left"`, `"control_right"`, `"super_left"`, `"super_right"`, `"shift_left"`, `"shift_right"`. + +## Code + +Settings for Warp's built-in code editor, file handling, and codebase indexing. + +**Section**: `[code]` + +### Editor + +**Section**: `[code.editor]` + +* `open_file_editor` — The editor used to open files. Type: string or object. Default: `"system_default"`. Options: `"system_default"`, `"warp"`, `"env_editor"`, or an external editor object such as `{ external_editor = "v_s_code" }`. Supported external editors: VS Code (`v_s_code`), VS Code Insiders (`v_s_code_insiders`), PyCharm (`py_charm`), IntelliJ IDEA (`intelli_j`), CLion (`c_lion`), RustRover (`rust_rover`), Sublime Text 4 (`sublime4`), Zed (`zed`), Cursor (`cursor`), Windsurf (`windsurf`), and others. +* `open_code_panels_file_editor` — The editor used to open files from code panels. Type: string or object. Default: `"warp"`. +* `open_file_layout` — The layout used when opening files in the editor. Type: string. Default: `"split_pane"`. Options: `"split_pane"`, `"new_tab"`. +* `prefer_markdown_viewer` — Whether to use the Markdown viewer when opening Markdown files. Type: boolean. Default: `true`. +* `prefer_tabbed_editor_view` — Whether to prefer opening files in a tabbed editor view. Type: boolean. Default: `true`. +* `show_code_review_button` — Whether to show the code review button on tabs. Type: boolean. Default: `true`. +* `auto_open_code_review_pane_on_first_agent_change` — Whether to automatically open the code review pane when the agent makes its first change. Type: boolean. Default: `false`. +* `show_code_review_diff_stats` — Whether to show lines added/removed counts on the code review button. Type: boolean. Default: `true`. +* `show_project_explorer` — Whether the project explorer is shown in the tools panel. Type: boolean. Default: `true`. +* `show_global_search` — Whether global file search is shown in the tools panel. Type: boolean. Default: `true`. +* `use_warp_as_default_editor` — Whether Warp is used as the default code editor. Type: boolean. Default: `false`. + +### Indexing + +**Section**: `[code.indexing]` + +* `agent_mode_codebase_context` — Whether Codebase Context is provided to the agent. Type: boolean. Default: `true`. +* `agent_mode_codebase_context_auto_indexing` — Whether automatic codebase indexing is enabled. Type: boolean. Default: `false`. + +## Keys + +Keyboard behavior settings. + +**Section**: `[keys]` + +* `ctrl_tab_behavior_setting` — Controls the behavior of `Ctrl+Tab`. Type: string. Default: `"activate_prev_next_tab"`. Options: `"activate_prev_next_tab"`, `"cycle_most_recent_session"`. + +## Notifications + +Settings that control desktop notification behavior. + +**Section**: `[notifications]` + +* `toast_duration_secs` — How long notification toasts are displayed, in seconds. Type: integer. Default: `8`. + +### Preferences + +**Section**: `[notifications.preferences]` + +* `mode` — Whether notifications are enabled, disabled, or not yet configured. Type: string. Default: `"unset"`. Options: `"unset"`, `"dismissed"`, `"enabled"`, `"disabled"`. +* `is_long_running_enabled` — Whether to notify when a long-running command completes. Type: boolean. Default: `true`. +* `long_running_threshold` — Threshold in seconds for long-running command notifications. Type: integer. Default: `30`. +* `is_agent_task_completed_enabled` — Whether to notify when an agent task completes. Type: boolean. Default: `true`. +* `is_needs_attention_enabled` — Whether to notify when a session needs attention. Type: boolean. Default: `true`. +* `is_password_prompt_enabled` — Whether to notify when a password prompt is detected. Type: boolean. Default: `true`. +* `play_notification_sound` — Whether to play a sound with notifications. Type: boolean. Default: `true`. + +## Privacy + +Settings that control telemetry, crash reporting, and secret redaction. + +**Section**: `[privacy]` + +* `telemetry_enabled` — Whether anonymous usage telemetry is collected. Type: boolean. Default: `true`. +* `crash_reporting_enabled` — Whether crash reports are sent. Type: boolean. Default: `true`. +* `custom_secret_regex_list` — Custom regex patterns for detecting and redacting secrets. Type: array of objects. Default: `[]`. + +Each item in `custom_secret_regex_list` has the format: + +```toml +[[privacy.custom_secret_regex_list]] +pattern = "sk-[A-Za-z0-9]{48}" +name = "OpenAI API key" +``` + +### Secret redaction + +**Section**: `[privacy.secret_redaction]` + +* `enabled` — Whether secret redaction is enabled to detect and obscure secrets in terminal output. Type: boolean. Default: `false`. +* `hide_secrets_in_block_list` — Whether to hide detected secrets in the block list using asterisks. Type: boolean. Default: `false`. +* `secret_display_mode_setting` — Controls how detected secrets are visually displayed. Type: string. Default: `"strikethrough"`. Options: `"asterisks"`, `"strikethrough"`, `"always_show"`. + +## System + +Low-level system and rendering settings. + +**Section**: `[system]` + +* `prefer_low_power_gpu` — Whether to prefer the integrated (low-power) GPU. Type: boolean. Default: `false`. +* `preferred_graphics_backend` — The preferred graphics backend (Windows). Type: string or null. Default: `null`. Options: `"dx12"`, `"vulkan"`, `"gl"`, `"metal"`, `null`. +* `linux_selection_clipboard` — Whether the Linux primary selection clipboard is used. Type: boolean. Default: `true`. + +## Text editing + +Settings that control text editing behavior in the input editor. + +**Section**: `[text_editing]` + +* `vim_mode_enabled` — Whether Vim keybindings are enabled. Type: boolean. Default: `false`. +* `vim_status_bar` — Whether the Vim status bar is displayed. Type: boolean. Default: `true`. +* `vim_unnamed_system_clipboard` — Whether the Vim unnamed register uses the system clipboard. Type: boolean. Default: `false`. +* `autocomplete_symbols` — Whether matching symbols like brackets and quotes are auto-completed. Type: boolean. Default: `true`. + +## Warp Drive + +Settings for Warp Drive (shared workflows, notebooks, and prompts). + +**Section**: `[warp_drive]` + +* `enabled` — Whether Warp Drive is enabled. Type: boolean. Default: `true`. +* `sorting_choice` — The sort order for items in Warp Drive. Type: string. Default: `"by_object_type"`. Options: `"by_timestamp"`, `"alphabetical_descending"`, `"alphabetical_ascending"`, `"by_object_type"`. + +## Warpify + +Settings for Warp features in SSH sessions and subshells. + +### SSH + +**Section**: `[warpify.ssh]` + +* `enable_ssh_warpification` — Whether to enable Warp features in SSH sessions. Type: boolean. Default: `true`. +* `enable_legacy_ssh_wrapper` — Whether the legacy SSH wrapper is enabled for SSH sessions. Type: boolean. Default: `true`. +* `use_ssh_tmux_wrapper` — Whether to use a tmux-based wrapper for SSH warpification. Type: boolean. Default: `false`. +* `ssh_extension_install_mode` — Controls SSH extension installation behavior. Type: string. Default: `"always_ask"`. Options: `"always_ask"` (always prompt before installing), `"always_install"` (auto-install and connect without prompting), `"never_install"` (fall back to legacy warpification). +* `ssh_hosts_denylist` — SSH hosts that should not trigger the warpification prompt. Type: array of strings. Default: `[]`. + +### Subshells + +**Section**: `[warpify.subshells]` + +* `added_subshell_commands` — Additional regex patterns for commands that should be recognized as subshells. Type: array of strings. Default: `[]`. +* `subshell_commands_denylist` — Commands that should not trigger the subshell warpification prompt. Type: array of strings. Default: `[]`. + +## Workflows + +Settings for workflow behavior. + +**Section**: `[workflows]` + +* `show_global_workflows_in_universal_search` — Whether to show global workflows in universal search results. Type: boolean. Default: `false`. + +## Accessibility + +Settings for screen reader support. + +**Section**: `[accessibility]` + +* `accessibility_verbosity` — The verbosity level for screen reader announcements. Type: string. Default: `"verbose"`. Options: `"verbose"` (includes help string), `"concise"` (value only). + +## Account + +Settings related to your Warp account. + +**Section**: `[account]` + +* `is_settings_sync_enabled` — Whether settings are synced across devices via the cloud. Type: boolean. Default: `false`. + +## Cloud platform + +Settings for third-party API key integration and cloud model configuration. + +### Third-party API keys + +**Section**: `[cloud_platform.third_party_api_keys]` + +* `aws_bedrock_credentials_enabled` — Whether Warp should use your local AWS credentials for Bedrock-enabled requests. Type: boolean. Default: `false`. +* `aws_bedrock_profile` — The AWS profile name to use for Bedrock credentials. Type: string. Default: `"default"`. +* `aws_bedrock_auto_login` — Whether to automatically run the AWS login command when Bedrock credentials expire. Type: boolean. Default: `false`. +* `aws_bedrock_auth_refresh_command` — The command to run to refresh AWS credentials for Bedrock. Type: string. Default: `"aws login"`. +* `can_use_warp_credits_with_byok` — Whether Warp credits can be used even when providing your own API key. Type: boolean. Default: `false`. + +## Global hotkey + +Settings for the global activation hotkey and dedicated hotkey window (Quake Mode). + +### Toggle all windows + +**Section**: `[global_hotkey.toggle_all_windows]` + +* `enabled` — Whether the hotkey that toggles visibility of all windows is enabled. Mutually exclusive with `global_hotkey.dedicated_window.enabled`. Type: boolean. Default: `false`. +* `keybinding` — The keybinding for the global activation hotkey. Format: modifiers and a key joined by `-`, for example `"cmd-shift-a"` or `"alt-enter"`. Type: string or null. Default: `null`. + +### Dedicated window (Quake Mode) + +**Section**: `[global_hotkey.dedicated_window]` + +* `enabled` — Whether the dedicated hotkey window is enabled. Mutually exclusive with `global_hotkey.toggle_all_windows.enabled`. Type: boolean. Default: `false`. + +**Section**: `[global_hotkey.dedicated_window.settings]` + +* `active_pin_position` — Screen edge where the hotkey window is pinned. Type: string. Options: `"top"`, `"bottom"`, `"left"`, `"right"`. +* `hide_window_when_unfocused` — Whether to hide the hotkey window when it loses focus. Type: boolean. +* `keybinding` — Keyboard shortcut to toggle the hotkey window. Type: string or null. +* `pin_screen` — Display to pin the hotkey window to. Type: string or object or null. Options: `"primary"`, `{ external = 1 }`, `null`. + +Window size percentages are configured per pin position: + +```toml +[global_hotkey.dedicated_window] +enabled = true + +[global_hotkey.dedicated_window.settings] +active_pin_position = "top" +hide_window_when_unfocused = true +keybinding = "ctrl-`" + +[global_hotkey.dedicated_window.settings.pin_position_to_size_percentages.top] +width = 100 +height = 30 + +[global_hotkey.dedicated_window.settings.pin_position_to_size_percentages.bottom] +width = 100 +height = 30 + +[global_hotkey.dedicated_window.settings.pin_position_to_size_percentages.left] +width = 40 +height = 100 + +[global_hotkey.dedicated_window.settings.pin_position_to_size_percentages.right] +width = 40 +height = 100 +``` diff --git a/src/content/docs/terminal/settings/index.mdx b/src/content/docs/terminal/settings/index.mdx new file mode 100644 index 0000000..d01ee9b --- /dev/null +++ b/src/content/docs/terminal/settings/index.mdx @@ -0,0 +1,176 @@ +--- +title: Settings file +description: >- + Configure Warp with a plain-text TOML settings file. Learn where it lives, + how it works with the Settings panel, and see common configuration examples. +--- + +Warp stores your preferences in a plain-text file called `settings.toml`. You can edit it directly in any text editor, check it into version control, or generate it with a script. Changes take effect immediately — no restart required. + +The settings file works alongside the graphical Settings panel. Changes you make in either place are reflected in the other. + +**Key features:** + +* **Hot-reload** — Warp watches `settings.toml` for changes and applies them instantly when you save the file. +* **Error recovery** — If the file contains invalid TOML or an unrecognized value, Warp shows a warning banner and falls back to defaults for the affected settings. Fix the file and the banner clears automatically. +* **Automatic migration** — When you upgrade to a version of Warp that includes the settings file, Warp automatically migrates your existing preferences into `settings.toml`. +* **Bidirectional sync with Settings UI** — Changes in the Warp **Settings** panel (`⌘+,` on macOS, `Ctrl+,` on Linux/Windows) write to `settings.toml`, and hand-edits to the file are reflected in the panel. +* **Agent-powered editing** — Ask Warp's agent to change settings for you using natural language (for example, "increase my font size to 16"). The bundled `modify-settings` skill handles the file update automatically. + +## Opening your settings file + +There are several ways to open `settings.toml`: + +* In the Warp app, go to **Settings** and click **Open settings file** at the bottom of the panel. +* Open the file directly in any editor at the path listed below for your platform and Warp release channel. + +## File location + +Depending on your platform and Warp release channel, `settings.toml` is located at: + +* **macOS** + * Stable — `~/.warp/settings.toml` + * Preview — `~/.warp-preview/settings.toml` +* **Linux** + * Stable — `~/.config/warp-terminal/settings.toml` + * Preview — `~/.config/warp-terminal-preview/settings.toml` +* **Windows** + * Stable — `%LOCALAPPDATA%\warp\Warp\config\settings.toml` + * Preview — `%LOCALAPPDATA%\warp\WarpPreview\config\settings.toml` + +## Settings file format + +The file uses [TOML v1.1](https://toml.io/en/v1.1.0) syntax. Settings are organized into **sections** (TOML tables) that group related options — for example, `[appearance.text]` contains font settings and `[agents.profiles]` contains agent permission settings. + +Here is a minimal example showing the structure: + +```toml +# Appearance settings +[appearance.text] +font_name = "JetBrains Mono" +font_size = 14.0 +line_height_ratio = 1.3 + +[appearance.themes] +theme = "dracula" + +# Terminal behavior +[terminal.input] +syntax_highlighting = true +honor_ps1 = false + +# Agent permissions +[agents.profiles] +agent_mode_execute_readonly_commands = true +``` + +### How sections map to TOML tables + +Each section in the settings file corresponds to a TOML table header in brackets. Subsections use dot-separated paths: + +* `[general]` — Top-level general settings like session restoration and tab placement +* `[appearance]` — Visual settings, with subsections like `[appearance.text]`, `[appearance.themes]`, `[appearance.cursor]` +* `[agents]` — Agent and AI settings, with subsections like `[agents.profiles]`, `[agents.warp_agent.input]` +* `[terminal]` — Terminal behavior settings, with subsections like `[terminal.input]` + +For the complete list of every available setting, see [All settings reference](/terminal/settings/all-settings/). + +## How settings are applied + +### Relationship between the Settings panel and the file + +The Warp Settings panel (`⌘+,` on macOS, `Ctrl+,` on Linux/Windows) and `settings.toml` represent the same underlying configuration. Changing a toggle in the Settings panel writes the new value to `settings.toml`. Editing `settings.toml` by hand updates the Settings panel the next time it reads the file. + +### Error banner + +When `settings.toml` has errors, Warp displays a dismissible warning banner at the top of the workspace. The banner includes an **Open settings file** button so you can jump directly to the file and fix the issue. Once you save a corrected file, the banner disappears automatically. + +## Common configurations + +### Change theme and font + +```toml +[appearance.themes] +theme = "cyber_wave" + +[appearance.text] +font_name = "Fira Code" +font_size = 15.0 +ligature_rendering_enabled = true +font_weight = "normal" +``` + +### Configure agent permissions + +```toml +[agents.profiles] +agent_mode_coding_permissions = "always_allow_reading" +agent_mode_execute_readonly_commands = true +agent_mode_command_execution_allowlist = [ + "cat(\\s.*)?", + "echo(\\s.*)?", + "find .*", + "grep(\\s.*)?", + "ls(\\s.*)?", + "which .*", +] +``` + +### Enable Vim keybindings + +```toml +[text_editing] +vim_mode_enabled = true +vim_status_bar = true +``` + +## Migrating from previous settings + +When you upgrade to a version of Warp that includes the settings file, Warp automatically migrates your existing preferences into `settings.toml`. No action is required — your customizations carry over and the file becomes the source of truth for all settings going forward. + +## Troubleshooting + +### "Your settings file contains an error" banner + +This banner appears when `settings.toml` has invalid TOML syntax or an unrecognized value. Click **Open settings file** in the banner to open the file and look for: + +* **Missing quotes** — String values must be wrapped in double quotes: `font_name = "Hack"`, not `font_name = Hack`. +* **Missing brackets** — Section headers require square brackets: `[appearance.text]`. +* **Wrong value types** — Check that numbers are numbers (`font_size = 13.0`), booleans are `true`/`false`, and enum values are valid strings. + +### Resetting to defaults + +Delete `settings.toml` (or rename it) and restart Warp. Warp falls back to built-in defaults for all settings. The file is re-created the next time you change a setting through the Settings panel. + +```bash +# Uncomment the two lines that match your platform and Warp release +# channel, then run them to back up and delete settings.toml. + +# Stable (macOS) +# cp ~/.warp/settings.toml ~/.warp/settings.toml.bak +# rm ~/.warp/settings.toml + +# Stable (Linux) +# cp ~/.config/warp-terminal/settings.toml ~/.config/warp-terminal/settings.toml.bak +# rm ~/.config/warp-terminal/settings.toml + +# Preview (macOS) +# cp ~/.warp-preview/settings.toml ~/.warp-preview/settings.toml.bak +# rm ~/.warp-preview/settings.toml + +# Preview (Linux) +# cp ~/.config/warp-terminal-preview/settings.toml ~/.config/warp-terminal-preview/settings.toml.bak +# rm ~/.config/warp-terminal-preview/settings.toml +``` + +### Settings not applying + +Confirm you're editing the correct file for your platform and Warp release channel (see [File location](#file-location) above). If you run multiple [Warp release channels](/support-and-community/community/warp-preview-and-alpha-program/), each channel has its own settings directory. + +## Related pages + +* [All settings reference](/terminal/settings/all-settings/) — Complete list of every available setting with descriptions, types, and defaults +* [Customizing Warp](/getting-started/quickstart/customizing-warp/) — Overview of all customization options +* [Custom themes](/terminal/appearance/custom-themes/) — Create and load custom YAML or Base16 themes +* [Keyboard shortcuts](/getting-started/keyboard-shortcuts/) — Customize keybindings +* [Settings Sync (Beta)](/terminal/more-features/settings-sync/) — Sync settings across machines diff --git a/src/content/docs/terminal/warpify/index.mdx b/src/content/docs/terminal/warpify/index.mdx new file mode 100644 index 0000000..946321e --- /dev/null +++ b/src/content/docs/terminal/warpify/index.mdx @@ -0,0 +1,19 @@ +--- +title: Warpify overview +description: >- + Warp support for Warpifying, or enabling Warp's features, in local or remote + sessions. +--- +import DemoVideo from '@components/DemoVideo.astro'; + +1. [Subshells](/terminal/warpify/subshells/), Warp supports enabling Warp features in subshells for bash, zsh, and fish. +2. [SSH](/terminal/warpify/ssh/), Warp supports a tmux powered wrapper that enables Warp features in remote (SSH) sessions. +3. [SSH Legacy](/terminal/warpify/ssh-legacy/), Warp supports a legacy wrapper that enables Warp features in remote (SSH) sessions. + +## Subshells + +<DemoVideo src="/assets/terminal/subshells-demo.mp4" label="Warpify Subshells Demo" /> + +## SSH + +<DemoVideo src="/assets/terminal/subshell-ssh-demo.mp4" label="Warpify SSH Demo" /> diff --git a/src/content/docs/terminal/warpify/ssh-legacy.mdx b/src/content/docs/terminal/warpify/ssh-legacy.mdx new file mode 100644 index 0000000..86372e0 --- /dev/null +++ b/src/content/docs/terminal/warpify/ssh-legacy.mdx @@ -0,0 +1,65 @@ +--- +title: Legacy SSH wrapper +description: >- + Legacy SSH wrapper that bootstraps Warp features on remote machines without + tmux. +--- +import DemoVideo from '@components/DemoVideo.astro'; + +:::note +If you are looking to troubleshoot the tmux SSH feature, see the [SSH](/terminal/warpify/ssh/). +::: + +When you SSH into a remote box, you get all the features of Warp without any configuration on your part. The input editor, auto-completions, and history search work the same, regardless of machine. + +:::caution +[Limitations of SSH](https://github.com/warpdotdev/Warp/issues/578) (as of May 2024): + +* The SSH Wrapper only supports `bash` or `zsh` shells in remote sessions. +* If you're using a different shell, you'll want to use `command ssh` directly (see below for more details). +* For zsh, xxd is required to bootstrap warp. +* For Windows, [Cygwin](https://www.cygwin.com/) is required to bootstrap the SSH Wrapper. +* RemoteCommand causes the ssh wrapper to fail. +* [Tmux is not currently supported.](https://github.com/warpdotdev/Warp/discussions/501) +::: + +:::note +If you're using zsh on the remote host, Warp creates a temp folder to act as the ZDOTDIR during the bootstrapping process and removes it when the shell is set up. +::: + +![SSH](../../../../assets/terminal/ssh-1.png) + +## Implementation + +We create a wrapper (around `/usr/bin/ssh`) to set up the shell for Warp's feature set. We authenticate normally using `/usr/bin/ssh`, and bootstrap the remote shell to work with Warp Blocks and the Input Editor. You can opt out of this functionality by invoking `command ssh` directly. + +* Warp takes over the prompt which enables us to build a modern input editor. +* Warp configures histcontrol to ignore commands with leading spaces. We do this so our bootstrapping code does not clutter the history. + +You can see the SSH wrapper by using `which warp_ssh_helper` in zsh, `type warp_ssh_helper` in bash. + +_Note:_ The ssh wrapper is only _initialized_ on your local machine. We don’t currently support bootstrapping nested ssh sessions. + +:::note +Warp [Completions](/terminal/command-completions/completions/) for ssh show entries in `~/.ssh/config` and `~/.ssh/known_hosts` +::: + +## Troubleshooting SSH + +### channel 2: open failed: connect failed: open failed + +If you're seeing these errors, you may have some config on your server (usually in `/etc/ssh/sshd_config`) preventing Warp's ControlMaster connection from working. In this state, completions that require information from your remote host won't work and your history also won't work. + +You should ensure that `MaxSessions` is either commented out or is at least `2`. + +Write access in `/etc/ssh/` typically requires sudo access. After any edits, you'd also need to restart the `sshd` daemon. + +### SSH Wrapper fails + +There are several [known issues with SSH Wrapper](https://github.com/warpdotdev/Warp/issues?q=is%3Aissue+is%3Aopen+sort%3Acreated-desc+label%3ABugs+label%3ASSH). As a workaround to the SSH Wrapper, you can add `command ssh` to your **Settings** > **Warpify** > **Subshells** > **Added commands**, then run `command ssh <user@server>` to connect to a remote session, this will attempt to enable Warp features as a [subshell](/terminal/warpify/subshells/). + +:::note +If the subshell workaround helps, we recommend you disable the SSH Wrapper in **Settings** > **Features** > **Session**. You'll need to start a new session before a change is reflected or try invoking the SSH binary directly with `command ssh`. +::: + +<DemoVideo src="/assets/terminal/subshell-ssh-demo.mp4" label="Command SSH subshell workaround" /> diff --git a/src/content/docs/terminal/warpify/ssh.mdx b/src/content/docs/terminal/warpify/ssh.mdx new file mode 100644 index 0000000..16316f3 --- /dev/null +++ b/src/content/docs/terminal/warpify/ssh.mdx @@ -0,0 +1,61 @@ +--- +title: SSH with Warp features +description: >- + Warpify SSH sessions with tmux to get Blocks, completions, and the input + editor on remote machines. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +:::note +Some coding features — including Codebase Context, code diffs, the code editor, and the file tree — are not yet available over SSH. See [Feature support over SSH](/code/ssh-feature-support/) for the full list. +::: + +:::caution +This page is dedicated to the SSH features powered by `tmux`. + +If you are looking to troubleshoot the legacy SSH implementation, see the [SSH (Legacy)](/terminal/warpify/ssh-legacy/). +::: + +<VideoEmbed url="https://youtu.be/S39jxLNfUlc" title="Warpify an SSH Session" /> + +Warpifying your SSH session gives you all the features of Warp while connected to a remote machine: the input editor, auto-completions, history search, and more. We achieve this by running commands like `ls` on the remote machine on your behalf. + +**Warpifying a remote SSH Session** [**will never make lasting changes to the remote machine without your explicit consent**](/terminal/warpify/ssh/#will-warpifying-a-remote-ssh-session-make-changes-to-the-remote-machine)**.** + +![SSH](../../../../assets/terminal/warpify_ssh_prompt.png) + +## FAQs + +#### Will Warpifying a remote SSH session make changes to the remote machine? + +Only to install [`tmux`](/terminal/warpify/ssh/#why-do-i-need-tmux-on-the-remote-machine) (a popular open source terminal multiplexer) and only with your explicit permission. If `tmux` is not installed, Warp will offer to install it for you and will show you the list of commands that will be run. You can always decline and continue to use your ssh session without some of Warp's features (or install `tmux` yourself and re-run Warpification [via the Command Palette](/terminal/warpify/ssh/#what-if-warp-fails-to-detect-my-ssh-session)). + +#### Why do I need `tmux` on the remote machine? + +`tmux` is used to asynchronously run commands on the remote machine without disrupting your interactive session. [tmux](https://github.com/tmux/tmux/wiki) is a popular open source terminal multiplexer, which lets you run multiple sessions within one ssh connection. It requires minimal permissions and is widely adopted (⭐ 35k+ on GitHub). Warpifying a remote SSH session uses [tmux Control Mode](https://github.com/tmux/tmux/wiki/Control-Mode) to run adhoc background tasks (like those required to autocomplete a `cd` command, or populate the contents of a custom prompt). + +#### Can I ssh to remote machines that I don't want to Warpify? + +Yes! You can always cancel Warpification and continue to use SSH, just without some of Warp's additional features. You can also explicitly add hosts to the Denylist to ensure you’re never asked to Warpify that host again. + +### Do I have to manually Warpify every time? + +After you successfully Warpify an SSH connection manually, we provide a brief script you can run to append a message at the end of your shell's rcfile. This allows us to know when your shell is ready to be Warpified, and be found at the bottom of your rcfile for the best results. + +![Setting up Auto-Warpify](../../../../assets/terminal/warpify_ssh_auto_script.png) + +#### What shells and operating systems are supported? + +At the time of writing, we support macOS and most flavors of Linux as remote hosts. Supported shells are `bash` and `zsh`. + +#### What if Warp fails to detect my SSH session? + +If you are ever in a remote SSH Session and would like to manually Warpify, you can do so by using the [Command Palette](/terminal/command-palette/) and searching for "Warpify SSH Session". + +#### What triggers SSH session detection for Warpification? + +If SSH Session Detection is enabled, Warp will detect when you run an `ssh` command with arguments that suggest it's starting an interactive session. If you've aliased `ssh` or are running it as part of a script, we will not perform SSH Session Detection. + +Once we have confidence you have successfully authenticated (by detecting `Last login:` or something resembling a basic prompt) we will prompt you to Warpify your active SSH session. + +If SSH Session Detection does not detect your session, you can still [Warpify manually](/terminal/warpify/ssh/#what-if-warp-fails-to-detect-my-ssh-session). diff --git a/src/content/docs/terminal/warpify/subshells.mdx b/src/content/docs/terminal/warpify/subshells.mdx new file mode 100644 index 0000000..3260ede --- /dev/null +++ b/src/content/docs/terminal/warpify/subshells.mdx @@ -0,0 +1,118 @@ +--- +title: Warpify subshells +description: >- + Warpify subshells in bash, zsh, and fish to get Warp features in nested + sessions. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +## What is a subshell? + +Within the context of Warp, a "subshell" is defined as any nested interactive shell session that's spawned and running within the context of an existing, running shell. This can be a nested session running locally on your machine, a shell session running within a Docker container, or a remote server accessed through SSH. [See more on SSH Warpification](/terminal/warpify/ssh/). + +Note that Warp's definition of a subshell differs from the more common definition of a Unix subshell, which typically refers to any shell process spawned as a child of the interactive shell. For example, in bash, a command wrapped in parentheses is executed in a subshell with its own PID and addressable memory space. + +## How to Warpify the subshell + +By default, Warp automatically recognizes the following commands as **subshell-compatible**: + +* bash, fish, zsh +* docker exec +* gcloud compute ssh +* eb ssh +* poetry shell + +When you run a command that's subshell-compatible, Warp will prompt you and invite you to "Warpify" the subshell which makes all of the modern IDE features of Warp available in that subshell. The list of subshell-compatible commands is configurable in Subshell settings as described [below](/terminal/warpify/subshells/#configuring-subshell-compatible-commands). + +:::note +bash, zsh, or fish (3.6 or above) must be set as the default shell within containers and ssh sessions for the Warpification of the subshells to work. +::: + +<DemoVideo src="/assets/terminal/subshells-demo.mp4" label="Subshells Demo" /> + +### Configuring subshell-compatible commands + +To configure subshell-compatible commands, navigate to **Settings** > **Warpify** > **Subshells**. + +#### Adding compatible commands + +You can add any command that spawns a bash, fish, or zsh subshell to ‘Added commands’ to make it eligible for "Warpification." + +Furthermore, you can add regular expressions to the Added commands list. Any commands that match an added regex will be eligible for "Warpification." + +#### Blocklisting commands + +Some types of subshells are not compatible, and you may also want to control Warp so it never invites you to "Warpify" the subshells for specific commands. When you add commands to the Blocklist, Warp will never invite you to "Warpify" subshells spawned by those commands. + +### Automatically "Warpify" subshells + +To remember your preferences for a command and bypass the confirmation banner, you can manually paste the appropriate snippet to the end of the RC file corresponding to your subshell (bash, fish, or zsh). + +```bash +# For zsh subshells, add to ~/.zshrc. +printf '\eP$f{"hook": "SourcedRcFileForWarp", "value": { "shell": "zsh"}}\x9c' + +# For bash subshells, add to ~/.bashrc or ~/.bash_profile. +printf '\eP$f{"hook": "SourcedRcFileForWarp", "value": { "shell": "bash"}}\x9c' + +# For fish subshells, add to ~/.config/fish/config.fish. +if status is-interactive + printf '\eP$f{"hook": "SourcedRcFileForWarp", "value": { "shell": "fish"}}\x9c' +end +``` + +Once added, Warp will automatically "Warpify" subsequent subshell sessions for the corresponding shell on the machine with the newly updated RC file. + +Under the hood, this snippet prints a Device Control String ([DCS](https://vt100.net/docs/vt510-rm/chapter4.html)) to be read by Warp, signaling that a subshell session has started and is ready to be "Warpified." In turn, Warp executes a setup script in the session that enables the full suite of Warp features like blocks, completions, and the input editor. + +For this reason, it’s best to ensure the snippet is added to the end of the RC file, so Warp does not attempt to execute the setup script before the shell has finished sourcing your RC file. + +To disable automatic integration, remove the snippet from the corresponding RC file. + +If you encounter issues in subshell sessions where the RC file is sourced, [file a GitHub issue](https://github.com/warpdotdev/Warp/issues/new/choose). + +## Background commands + +Warp runs background commands to power useful features like completions, syntax highlighting, and command corrections. For example, to provide completions for git checkout, Warp runs a background command that lists all git branches in the current repo. + +In local subshell sessions, these commands are run in forked shell processes, isolated from your interactive shell session. This is the same implementation used for any non-subshell session. + +In remote sessions, however, Warp takes a different approach – while a forked shell process is running on your local machine (where the Warp app is running), your remote session might be running on a server elsewhere. In these cases, Warp takes advantage of the session’s “idle time” – when no command is currently running – to run background commands directly in the session itself. These commands are executed in a non-interactive subshell process to prevent modifications to the session state (they cannot modify an environment variable, for instance). + +### Show/hide background blocks + +By default, blocks for background commands are hidden. To show background command blocks, select ‘Show background blocks’ in the ‘Blocks’ menu of the macOS menu bar. + +### Disable background commands in remote sessions + +We understand that some developers may want to disable background commands for certain or all environments. + +To disable background commands in remote subshell sessions, you can execute the following command in a top-level terminal session: + +<Tabs> + <TabItem label="macOS"> + Update the settings defaults located in `dev.warp.Warp-Stable` to include the following name-value pair: `"DisableInBandCommands": "true"`. + + ```bash + defaults update dev.warp.Warp-Stable DisableInBandCommands true + ``` + </TabItem> + <TabItem label="Windows"> + Update the settings registry located at `HKCU:\Software\Warp.dev\Warp` to include the following name-value pair: `"DisableInBandCommands": "true"`. + + ```powershell + Set-ItemProperty -Path "HKCU:\SOFTWARE\Warp.dev\Warp" -Name DisableInBandCommands -Value true + ``` + </TabItem> + <TabItem label="Linux"> + Update the settings file located at `~/.config/warp-terminal/user_preferences.json` to include the following name-value pair: `"DisableInBandCommands": "true"`. + + ```bash + cd ~/.config/warp-terminal/ + jq '.prefs += {"DisableInBandCommands": "true"}' user_preferences.json > tmp.json && mv tmp.json user_preferences.json + ``` + </TabItem> +</Tabs> + +This will effectively disable tab completions, syntax highlighting, command corrections, and the git status prompt indicator in remote subshells. diff --git a/src/content/docs/terminal/windows/configurable-toolbar.mdx b/src/content/docs/terminal/windows/configurable-toolbar.mdx new file mode 100644 index 0000000..892e560 --- /dev/null +++ b/src/content/docs/terminal/windows/configurable-toolbar.mdx @@ -0,0 +1,75 @@ +--- +title: Configurable toolbar +description: >- + Reorder, hide, and move panel toggle buttons between the left and right + sides of Warp's header toolbar to match your workflow. +--- +import VideoEmbed from '@components/VideoEmbed.astro'; + +The header toolbar holds the panel toggle buttons for the tabs panel, tools panel, agent management, Code Review, and notifications mailbox. Instead of a fixed layout, you can rearrange these buttons, move them between the left and right sides of the header, or hide the ones you don't use. The side a button lives on also determines which side of the window its panel opens on, so you can tune Warp's layout to match how you work. + +The configurable toolbar works with both [horizontal tabs](/terminal/windows/tabs/) and [vertical tabs](/terminal/windows/vertical-tabs/). + +<VideoEmbed url="https://www.loom.com/share/292d126ecf7148f296fc8685e451790f?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Configurable toolbar demo" /> + +## Key features + +* **Reorder items within a side** - Drag toolbar chips to change the left-to-right order on either side of the header. +* **Move items across sides** - Drag a chip between the left and right drop zones to move its button (and the panel it opens) to the other side of the window. +* **Hide items you don't need** - Remove a chip from both sides to hide the button. Removed items become available again, so you can drop them back in later. +* **Side placement drives panel side** - Moving the tools panel, tabs panel, or code review button flips the corresponding panel to open from the same side, with resize handles, borders, and anchored popups following along. +* **Persistent across sessions** - Your layout is saved to settings and survives app restarts. + +## Configurable items + +The following header buttons can be rearranged or hidden: + +* **Tabs panel** - Toggles the [vertical tabs](/terminal/windows/vertical-tabs/) sidebar. +* **Tools panel** - Toggles the panel that contains the project explorer, global search, [Warp Drive](/knowledge-and-collaboration/warp-drive/), and conversation history. +* **Agent management** - Toggles the agent management view for [cloud agents](/agent-platform/cloud-agents/managing-cloud-agents/). +* **Code review** - Toggles the [Code Review](/code/code-review/) panel. +* **Notifications mailbox** - Toggles the [agent notifications](/agent-platform/capabilities/agent-notifications/) mailbox. + +The search bar and profile avatar are fixed and can't be repositioned. + +An item only appears in the toolbar when its prerequisites are met. For example, the tabs panel button requires [vertical tabs](/terminal/windows/vertical-tabs/) to be enabled, and agent management requires Agent Mode to be enabled. If an item's prerequisite becomes unavailable later, the button disappears but your saved layout is preserved, so the button reappears once the prerequisite is met again. + +## Default layout + +The default layout matches Warp's standard header: + +* **Left** - Tabs panel, tools panel, agent management. +* **Right** - Code review, notifications mailbox. + +## Editing the toolbar + +You can open the toolbar editor from the header or from Settings. + +### From the header + +Right-click any toolbar button (or any empty space between the buttons and the search bar) and select **Rearrange toolbar items**. The configurator modal opens. + +### From Settings + +1. In the Warp app, navigate to **Settings** > **Appearance** > **Tabs**. +2. Click **Edit toolbar**. + +## How side placement affects panels + +Moving a button to the opposite side also moves where its panel opens, and Warp flips associated UI to stay readable: + +* **Tabs panel** - Opens its sidebar on whichever side its button sits. The hover detail sidecar, action buttons, and right-click menu flip to face the center of the screen. +* **Tools panel** - Opens on the side its button sits. Warp Drive hover previews, kebab menus, and dialogs flip toward the center. The resize handle and border switch to the edge facing the main content. +* **Code review** - Opens on the side its button sits, with a matching resize handle. +* **Agent management** - Replaces the main content area when opened, so side placement only affects the button's position, not where the view renders. +* **Notifications mailbox** - The popover anchors under its button, and notification toasts appear on the same side as the mailbox button. + +When multiple panels are open on the same side, they render in the order their buttons appear in the toolbar. For example, if the left-side order is code review, tabs panel, tools panel, the panels open in that same order from left to right, with the main content to their right. + +## Related pages + +* [Vertical tabs](/terminal/windows/vertical-tabs/) - The sidebar toggled by the tabs panel button. +* [Code Review panel](/code/code-review/) - The panel toggled by the code review button. +* [Agent notifications](/agent-platform/capabilities/agent-notifications/) - The mailbox toggled by the notifications button. +* [Managing cloud agents](/agent-platform/cloud-agents/managing-cloud-agents/) - The view toggled by the agent management button. +* [Warp Drive](/knowledge-and-collaboration/warp-drive/) - One of the views available in the tools panel. diff --git a/src/content/docs/terminal/windows/global-hotkey.mdx b/src/content/docs/terminal/windows/global-hotkey.mdx new file mode 100644 index 0000000..52a8790 --- /dev/null +++ b/src/content/docs/terminal/windows/global-hotkey.mdx @@ -0,0 +1,62 @@ +--- +title: Global Hotkey +description: >- + Show or hide Warp instantly with a global hotkey, including a dedicated + Quake-style drop-down window. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import { Tabs, TabItem } from '@astrojs/starlight/components'; + +:::note +On macOS, [system keyboard shortcuts](https://support.apple.com/en-us/HT201236) like `CMD-ESC`, `CMD-BACKTICK`, `CMD-TAB`, `CMD-PERIOD`, and `CMD-TILDE` need to be [unbound](https://support.apple.com/guide/mac-help/keyboard-shortcuts-mchlp2262/mac) before you can use them in Warp. +::: + +:::caution +On Linux, the Global Hotkey may not work for some X11 window managers that do not implement [Extended Window Manager Hints](https://en.wikipedia.org/wiki/Extended_Window_Manager_Hints). Some examples include: [sowm](https://github.com/dylanaraps/sowm), [catwm](https://github.com/pyknite/catwm), [Fvwm](https://www.fvwm.org/), [dwm](https://dwm.suckless.org/), [2bWM](https://github.com/venam/2bwm), [monsterwm](https://github.com/c00kiemon5ter/monsterwm), [TinyWM](https://github.com/mackstann/tinywm), [x11fs](https://github.com/sdhand/x11fs), [XMonad](https://xmonad.org/) +::: + +## How to access it + +### Dedicated window + +Dedicated Window allows you to customize the windows' pinned position and its width and height ratio relative to your active screen size (also known as Quake Mode). + +1. Open **Settings** > **Features** > **Keys** and select "Dedicated hotkey window" from the Global Hotkey dropdown to enable the feature. +2. Configure the keybinding, the windows position, screen, and relative size or uncheck "Autohides on the loss of keyboard focus" which will cause the dedicated Hotkey Window to stay on top when triggered regardless of mouse or keyboard focus. + +:::caution +On Linux and Windows, Warp does not support the "Autohides on the loss of keyboard focus" feature. +::: + +### Show/hide all windows + +Show/Hide All Windows allows you to configure a shortcut to show/hide all Warp windows. + +1. Open **Settings** > **Features** > **Keys** and select "Show/hide all windows" from the Global Hotkey dropdown to enable the feature. +2. Configure your preferred keybinding. + +:::caution +On Linux, hidden windows may not appear in your `ALT-TAB` window switcher menu. Furthermore, the ordering of windows beyond the top window may change after toggling. +::: + +## How it works + +<DemoVideo src="/assets/terminal/Dedicated-Window.mp4" label="Global Hotkey - Dedicated Window Demo" /> + +<DemoVideo src="/assets/terminal/Show-Hide-All-Windows.mp4" label="Global Hotkey - Show/Hide All Windows Demo" /> + +## Troubleshooting hotkey dedicated window + +Review platform-specific instructions for troubleshooting the global hotkey below + +<Tabs> + <TabItem label="macOS"> + If the keybinding doesn't work, check under `System Preferences > Security & Privacy > Accessibility` and tick the checkbox to grant Warp access. + </TabItem> + <TabItem label="Windows"> + On Windows, there are no known issues with Global Hotkey Dedicated Window. If you find an issue, please [send feedback](/support-and-community/troubleshooting-and-support/sending-us-feedback/) to let us know. + </TabItem> + <TabItem label="Linux"> + The hotkey window may appear on the incorrect monitor under certain window sizes. For example, with GNOME, if the hotkey window is supposed to show on a monitor having the taskbar (GNOME Panel), and the window height is 100%, causing an overlap, the hotkey window may fallback to showing on an external monitor if you have one. Try working around this by setting a window height to a lesser percentage, e.g. 90%. + </TabItem> +</Tabs> diff --git a/src/content/docs/terminal/windows/index.mdx b/src/content/docs/terminal/windows/index.mdx new file mode 100644 index 0000000..b1f8d7b --- /dev/null +++ b/src/content/docs/terminal/windows/index.mdx @@ -0,0 +1,29 @@ +--- +title: Windows and Tabs +description: >- + Manage Warp windows, tabs, vertical tabs, split panes, and tab + configurations with global hotkeys and reusable layouts. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +1. [Tabs](/terminal/windows/tabs/) allow you to organize a window into multiple terminal sessions. +2. [Vertical Tabs](/terminal/windows/vertical-tabs/) replace the horizontal tab bar with a sidebar that shows rich metadata and drag-and-drop management for every tab and pane. +3. [Split Panes](/terminal/windows/split-panes/) allows you to divide a Tab into multiple rectangular _panes_, each of which is a unique terminal session. +4. [Tab Configs](/terminal/windows/tab-configs/) let you define reusable tab setups in a simple TOML file +5. [Global Hotkey](/terminal/windows/global-hotkey/) is a configurable shortcut that can show/hide a dedicated window or all windows on your chosen desktop regardless of whether the app is focused. +6. [Launch Configurations (Legacy)](/terminal/sessions/launch-configurations/) support saving a configuration of windows, tabs, and panes to open later. + +## Tabs + +<VideoEmbed url="https://www.loom.com/share/84d15cc7eb5a4a668bb86be9e827f261?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Tabs Demo" /> + +## Split Panes + +<VideoEmbed url="https://www.loom.com/share/c1104b51cab848a9bef6792ec4fd8421?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Split Panes Demo" /> + +## Global Hotkey + +<DemoVideo src="/assets/terminal/Dedicated-Window.mp4" label="Global Hotkey - Dedicated Window Demo" /> + +<DemoVideo src="/assets/terminal/Show-Hide-All-Windows.mp4" label="Global Hotkey - Show/Hide All Windows Demo" /> diff --git a/src/content/docs/terminal/windows/split-panes.mdx b/src/content/docs/terminal/windows/split-panes.mdx new file mode 100644 index 0000000..062d7b4 --- /dev/null +++ b/src/content/docs/terminal/windows/split-panes.mdx @@ -0,0 +1,52 @@ +--- +title: Split panes +description: >- + The split panes feature allows you to divide a tab into multiple rectangular + panes, each of which is a unique terminal session. +--- +import DemoVideo from '@components/DemoVideo.astro'; +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +## How to use split panes + +<Tabs> + <TabItem label="macOS"> + * Split panes to the right / down with `CMD-D` / `SHIFT-CMD-D` or in any direction by right-clicking on any Pane. + * Activate the Previous / Next Pane with `CMD-[` / `CMD-]` or by clicking a pane. + * Navigate among split panes with `OPT-CMD-ARROW`, the active pane will be marked with a triangle in the top corner. + * Toggle Maximize Pane with `CMD-SHIFT-ENTER`. + * Close the active Pane with `CMD-W`. + * You can also drag and drop panes. Click and drag a Pane’s header around a given tab, drag the Pane to the tab bar to move it to another Tab, or make it into a Tab. + </TabItem> + <TabItem label="Windows"> + * Split Panes to the right / down with `CTRL-SHIFT-D` / `CTRL-SHIFT-E` or in any direction by right-clicking on any Pane. + * Activate the Previous / Next Pane with `CTRL-SHIFT-{` / `CTRL-SHIFT-}` or by clicking a pane. + * Navigate among Split Panes with `CTRL-ALT-ARROW`, the active pane will be marked with a triangle in the top corner. + * Toggle Maximize Pane with `CTRL-SHIFT-ENTER`. + * Close the active Pane with `CTRL-SHIFT-W`. + * You can also drag and drop panes. Click and drag a Pane’s header around a given tab, drag the Pane to the tab bar to move it to another Tab, or make it into a Tab. + </TabItem> + <TabItem label="Linux"> + * Split Panes to the right / down with `CTRL-SHIFT-D` / `CTRL-SHIFT-E` or in any direction by right-clicking on any Pane. + * Activate the Previous / Next Pane with `CTRL-SHIFT-{` / `CTRL-SHIFT-}` or by clicking a pane. + * Navigate among Split Panes with `CTRL-ALT-ARROW`, the active pane will be marked with a triangle in the top corner. + * Toggle Maximize Pane with `CTRL-SHIFT-ENTER`. + * Close the active Pane with `CTRL-SHIFT-W`. + * You can also drag and drop panes. Click and drag a Pane’s header around a given tab, drag the Pane to the tab bar to move it to another Tab, or make it into a Tab. + </TabItem> +</Tabs> + +:::note +You can quickly find all the **pane** shortcuts by using the [Command Palette](/terminal/command-palette/). You can also remap the shortcuts to your liking. See [Custom Keyboard Shortcuts](/getting-started/keyboard-shortcuts/#custom-keyboard-shortcuts) for more details. +::: + +### CTRL-TAB behavior + +`CTRL-TAB` shortcut defaults to activate the previous / next [Tabs](/terminal/windows/tabs/). You can configure the shortcut to cycle the most recent session, including any split panes, in **Settings** > **Features** > **Keys** > **Ctrl-Tab behavior** + +## How split panes work + +<VideoEmbed url="https://www.loom.com/share/c1104b51cab848a9bef6792ec4fd8421?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Split Panes Demo" /> + +<DemoVideo src="/assets/terminal/split-panes-dragging-demo.mp4" label="Split Panes Drag and Drop Demo" /> diff --git a/src/content/docs/terminal/windows/tab-configs.mdx b/src/content/docs/terminal/windows/tab-configs.mdx new file mode 100644 index 0000000..f44614c --- /dev/null +++ b/src/content/docs/terminal/windows/tab-configs.mdx @@ -0,0 +1,205 @@ +--- +title: Tab Configs +description: >- + Tab Configs let you define reusable tab setups — including directory, + startup commands, pane layout, shell, and theme — in a simple TOML file. +--- + +Tab Configs let you define reusable tab setups — including directory, startup commands, pane layout, shell, and theme — in a simple TOML file. Select a Tab Config from the `+` menu to open a fully configured tab with a single click. + +## How Tab Configs work + +Each Tab Config is a `.toml` file stored in `~/.warp/tab_configs/`. Every file defines a single tab layout with optional pane splits, startup commands, and parameterized inputs. Tab Configs appear in the `+` menu alongside your existing tabs, so you can launch a preconfigured workspace instantly. + +## Creating a Tab Config + +### From the UI + +1. Click the **+** button in the tab bar to open the new-tab menu. +2. Click **+ New tab config**. Warp creates a new `.toml` file in `~/.warp/tab_configs/` and opens it for editing. + +### Manually + +1. Create a new `.toml` file in `~/.warp/tab_configs/`. Use snake_case for the file name (e.g., `dev_server.toml`). +2. Define the tab layout using the schema below, then save the file. The new config appears in the `+` menu automatically. + +### Save an existing tab as a Tab Config + +You can also capture a tab's current state as a reusable Tab Config without writing TOML. Right-click any tab in the [vertical tabs](/terminal/windows/vertical-tabs/) panel or horizontal tab bar to open the context menu, then click **Save as new config**. Warp generates a `.toml` file from the tab's layout, commands, and directory and adds it to the `+` menu. + +![Tab context menu in Warp's vertical tabs panel with Save as new config highlighted](../../../../assets/terminal/save-new-tab-config.png) + +## Managing Tab Configs + +Saved Tab Configs appear in the `+` menu for quick access. When you hover a Tab Config in the menu, a **sidecar panel** appears alongside it with options to: + +* **Edit config** — Open the underlying `.toml` file for manual editing. The editor also shows a footer to invoke the **update tab config** skill, so you can describe changes in natural language and have Warp's agent apply them. +* **Remove** — Remove the Tab Config from the `+` menu. +* **Make default** — Assign the Tab Config as the default `Cmd T` action for new tabs. + +![Warp's + menu open with a saved screenshots_tab_config entry highlighted, and a sidecar panel showing Make default, Edit config, and Remove action buttons](../../../../assets/terminal/saved-tab-config-menu.png) + +## Using skills to manage Tab Configs + +Warp includes built-in skills for creating and modifying Tab Configs through natural language: + +* **Create Tab Config** — Generate a new Tab Config from a description (e.g., "create a 2x2 grid with one pane running my dev server"). +* **Update Tab Config** — Modify an existing Tab Config by describing the changes you want. + +To use these skills, type `/skills` in Agent Mode and select the tab config skill, or use the footer that appears when editing a Tab Config file. + +## Tab Config TOML schema + +### Top-level fields + +* **`name`** (required, string) — display name shown in the `+` menu. +* **`title`** (optional, string) — custom tab title. Supports `{{param}}` template variables. +* **`color`** (optional, string) — tab color. One of: `"black"`, `"red"`, `"green"`, `"yellow"`, `"blue"`, `"magenta"`, `"cyan"`, `"white"`. Actual color values are derived from your Warp [Theme](/terminal/appearance/themes/). + +### Pane list + +All panes are defined in a flat `[[panes]]` array. The first entry is the root of the pane tree. Each entry is either a **split node** (branch) or a **leaf node**. + +#### Leaf node fields + +* **`id`** (required, string) — unique identifier for this pane. Use descriptive names like `"editor"` or `"server"`. +* **`type`** (required, string) — `"terminal"` (standard shell), `"agent"` (opens in Agent Mode), or `"cloud"` (cloud mode pane, no local shell). +* **`directory`** (optional, string) — initial working directory. Supports `~` expansion and `{{param}}` template variables. +* **`commands`** (optional, array of strings) — commands to run in sequence when the tab opens. +* **`shell`** (optional, string) — shell executable to use for this pane (e.g. `"pwsh"`, `"zsh"`, `"bash"`, `"fish"`). Only applies to `terminal` and `agent` pane types. If omitted or the specified shell is not installed, the user's default shell is used. +* **`is_focused`** (optional, bool) — set to `true` on at most one pane to give it initial focus. + +#### Split node fields + +* **`id`** (required, string) — unique identifier for this split. +* **`split`** (required, string) — `"horizontal"` (children arranged left-to-right) or `"vertical"` (children arranged top-to-bottom). +* **`children`** (required, array of strings) — ordered list of child pane `id` values. Must contain at least 2 entries. Order determines visual order. + +:::note +All children within a split are equally sized. There are no flex or proportion values. +::: + +### Parameters + +Parameters let users fill in values at open time via a modal prompt. Declare them with `[params.<name>]` tables and reference them in `directory`, `commands`, and `title` using `{{name}}` syntax. + +Each parameter has: + +* **`type`** (optional, string) — `"text"` (default, freeform input), `"branch"` (Git branch picker), or `"repo"` (repository picker). +* **`description`** (optional, string) — label shown in the fill-in UI. +* **`default`** (optional, string) — default value. + +`{{autogenerated_branch_name}}` is a reserved template variable. If a Tab Config references it, Warp generates a unique worktree branch name on each open instead of prompting the user. + +## Examples + +### Single pane + +A simple config that opens a terminal in a project directory and starts a dev server: + +```toml +name = "Dev Server" + +[[panes]] +id = "main" +type = "terminal" +directory = "~/code/my-app" +commands = ["npm run dev"] +``` + +### Two panes side by side + +An editor and server running in parallel, with the editor focused: + +```toml +name = "Editor + Server" +color = "green" + +[[panes]] +id = "root" +split = "horizontal" +children = ["editor", "server"] + +[[panes]] +id = "editor" +type = "terminal" +directory = "~/code/my-app" +commands = ["nvim ."] +is_focused = true + +[[panes]] +id = "server" +type = "terminal" +directory = "~/code/my-app" +commands = ["npm run dev"] +``` + +### Cross-shell development + +A config that opens two panes side by side, each with a different shell: + +```toml +name = "Cross Shell" +color = "cyan" + +[[panes]] +id = "root" +split = "horizontal" +children = ["bash_pane", "pwsh_pane"] + +[[panes]] +id = "bash_pane" +type = "terminal" +shell = "bash" +directory = "~/code/my-app" +is_focused = true + +[[panes]] +id = "pwsh_pane" +type = "terminal" +shell = "pwsh" +directory = "~/code/my-app" +``` + +### Worktree with parameters + +A parameterized config that creates a new Git worktree on open: + +```toml +name = "New Worktree" +title = "{{branch_name}}" + +[[panes]] +id = "main" +type = "terminal" +directory = "{{repo}}" +commands = [ + "git worktree add -b {{branch_name}} ../{{branch_name}} {{base_branch}}", + "cd ../{{branch_name}}", +] + +[params.repo] +type = "repo" +description = "Repository path" + +[params.base_branch] +type = "branch" +description = "Base branch to branch from" + +[params.branch_name] +type = "text" +description = "New branch name" +default = "my-feature" +``` + +### Quick worktree setup + +You can also create a worktree-based Tab Config directly from the `+` menu by clicking **New worktree config** and selecting the repo you want your worktree to be from. Warp generates the Tab Config automatically and saves it for future use. + +## Related pages + +* [Launch Configurations (Legacy)](/terminal/sessions/launch-configurations/) — the previous session configuration format. Existing configs still work, but Tab Configs are the recommended approach for new setups. +* [Tabs](/terminal/windows/tabs/) — tab management, keyboard shortcuts, and behavior settings +* [Themes](/terminal/appearance/themes/) — customize the colors used by tab color settings +* [Working Directory](/terminal/more-features/working-directory/) — how Warp resolves working directories +* [Third-Party CLI Agents](/agent-platform/cli-agents/overview/) — use the `"agent"` pane type to open tabs in Agent Mode diff --git a/src/content/docs/terminal/windows/tabs.mdx b/src/content/docs/terminal/windows/tabs.mdx new file mode 100644 index 0000000..6423b38 --- /dev/null +++ b/src/content/docs/terminal/windows/tabs.mdx @@ -0,0 +1,89 @@ +--- +title: Tabs +description: >- + Organize your window into multiple terminal sessions with customizable tabs, + complete with titles and ANSI colors. +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import VideoEmbed from '@components/VideoEmbed.astro'; + +:::note +New Tabs will default to the active Tabs’ current [Working Directory](/terminal/more-features/working-directory/) and the actual color values will be automatically derived from your Warp [Theme](/terminal/appearance/themes/). +::: + +## How to use Tabs + +<Tabs> + <TabItem label="macOS"> + * Right-click on the new Tab button `+` to make a new tab, restore closed tab, or run a saved [Launch Configuration](/terminal/sessions/launch-configurations/). + * Open a new Tab with `CMD-T` or by clicking on the `+` in the top bar. + * Close the current Tab with `CMD-W` or by clicking on the `X` on hover over a Tab. + * Reopen closed tabs with `SHIFT-CMD-T`. + * Move a Tab to the Left / Right with `CTRL-SHIFT-LEFT` / `CTRL-SHIFT-RIGHT` or by clicking and dragging a Tab. + * Activate the Previous / Next Tab with `SHIFT-CMD-{` / `SHIFT-CMD-}` or by clicking a Tab. + * Activate the first through eighth Tabs with `CMD-1` thru `CMD-8`. + * Switch to the last Tab with `CMD-9`. + * Double-click a Tab to rename it. + * Right-clicking on a Tab reveals more options you can explore within the [Command Palette](/terminal/command-palette/) or [Keyboard Shortcuts](/getting-started/keyboard-shortcuts/#fundamentals). + </TabItem> + <TabItem label="Windows"> + * Right-click on the new Tab button `+` to make a new tab, restore closed tab, or run a saved [Launch Configuration](/terminal/sessions/launch-configurations/). + * Open a new Tab with `CTRL-SHIFT-T` or by clicking on the `+` in the top bar. + * Close the current Tab with `CTRL-SHIFT-W` or by clicking on the `x` on hover over a Tab. + * Reopen closed tabs with `CTRL-ALT-T`. + * Move a Tab to the Left / Right with `CTRL-SHIFT-LEFT` / `CTRL-SHIFT-RIGHT` or by clicking and dragging a Tab. + * Activate the Previous / Next Tab with `CTRL-PGUP` / `CTRL-PGDN` or by clicking a Tab. + * Activate the first through eighth Tabs with `CTRL-1` thru `CTRL-8`. + * Switch to the last Tab with `CTRL-9`. + * Double-click a Tab to rename it. + * Right-clicking on a Tab reveals more options you can explore within the [Command Palette](/terminal/command-palette/) or [Keyboard Shortcuts](/getting-started/keyboard-shortcuts/#fundamentals). + </TabItem> + <TabItem label="Linux"> + * Right-click on the new Tab button `+` to make a new tab, restore closed tab, or run a saved [Launch Configuration](/terminal/sessions/launch-configurations/). + * Open a new Tab with `CTRL-SHIFT-T` or by clicking on the `+` in the top bar. + * Close the current Tab with `CTRL-SHIFT-W` or by clicking on the `x` on hover over a Tab. + * Reopen closed tabs with `CTRL-ALT-T`. + * Move a Tab to the Left / Right with `CTRL-SHIFT-LEFT` / `CTRL-SHIFT-RIGHT` or by clicking and dragging a Tab. + * Activate the Previous / Next Tab with `CTRL-PGUP` / `CTRL-PGDN` or by clicking a Tab. + * Activate the first through eighth Tabs with `CTRL-1` thru `CTRL-8`. + * Switch to the last Tab with `CTRL-9`. + * Double-click a Tab to rename it. + * Right-clicking on a Tab reveals more options you can explore within the [Command Palette](/terminal/command-palette/) or [Keyboard Shortcuts](/getting-started/keyboard-shortcuts/#fundamentals). + </TabItem> +</Tabs> + +:::tip +**Terminal Tip**\ +Using your `.zshrc` or `.bashrc` files on macOS or Linux, you can set a new Tab name: + +```bash +# Set name, where MyTabName would be whatever you want to see in the Tab ( either a fixed string, $PWD, or something else ) +function set_name () { + export WARP_DISABLE_AUTO_TITLE=true + echo -ne "\033]0;MyTabName\007" +} +# Add the function to the environment variable in either Zsh or Bash +if [ -n "$ZSH_VERSION" ]; then + preexec_functions+=(set_name) +elif [ -n "$BASH_VERSION" ]; then + PROMPT_COMMAND='set_name' +fi +``` +Learn more about Tab names [here](https://learn.microsoft.com/en-us/windows/terminal/tutorials/tab-title#set-the-shells-title). +::: + +### Tab Restoration + +Tab Restoration enables you to reopen recently closed tabs for up to 60 seconds. Configure this feature in **Settings** > **Features** > **Session** > **Enable reopening of closed sessions** + +### CTRL-TAB Behavior + +`CTRL-TAB` shortcut defaults to activate the previous / next Tab. You can configure the shortcut to cycle the most recent session, including any [Split Panes](/terminal/windows/split-panes/), in **Settings** > **Features** > **Keys** > **Ctrl-Tab behavior** + +### Tabs Behavior + +Please see our [Appearance > Tabs Behavior](/terminal/appearance/tabs-behavior/) docs for more Tab related settings. + +### How Tabs work + +<VideoEmbed url="https://www.loom.com/share/84d15cc7eb5a4a668bb86be9e827f261?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" title="Tabs Demo" /> diff --git a/src/content/docs/terminal/windows/vertical-tabs.mdx b/src/content/docs/terminal/windows/vertical-tabs.mdx new file mode 100644 index 0000000..b07bf1c --- /dev/null +++ b/src/content/docs/terminal/windows/vertical-tabs.mdx @@ -0,0 +1,161 @@ +--- +title: Vertical tabs +description: >- + The vertical tabs panel replaces Warp's horizontal tab bar with a sidebar + The vertical tabs panel replaces the horizontal tab bar with a sidebar + showing rich metadata, drag-and-drop management, and display options for + tabs and panes. and panes. +--- + +The vertical tabs panel is a sidebar that replaces the traditional horizontal tab bar with a richer, more powerful tab management surface. Instead of a single row of tab titles, the panel displays every tab and pane with contextual metadata — Git branch, working directory, agent conversation status, diff stats, and more. Scan and switch between workstreams without losing context. + +Vertical tabs are especially useful when running multiple coding agents side by side, giving you a clear overview of each session's state without switching tabs. + +## Key features + +### Rich metadata and status + +* **Pane metadata** - See working directory, Git branch, agent conversation status, diff stats, and PR badges at a glance for every pane. +* **Agent status badges** - Pane icons display a colored badge overlay showing agent state (in progress, done, errored, cancelled, or blocked). [Third-party CLI agents](/agent-platform/cli-agents/overview/) like Claude Code, Codex, and Gemini CLI display their brand icon and color alongside badges. +* **Notification indicators** - An accent-colored dot appears on pane rows with unread agent activity, so you can spot sessions that need attention without switching tabs. + +### Display modes and customization + +* **Pane or tab view** - Display every split pane as its own row (**Panes**) or show only the focused pane per tab (**Tabs**). +* **Compact and expanded modes** - Choose between a dense single-line view (default) or a detailed multi-line layout with full metadata. +* **Configurable pane titles** - Control which metadata appears first: last command or conversation, working directory, or Git branch. +* **Hover detail sidecar** - Hover any pane row to see full, un-clipped metadata in a floating detail card without changing focus. + +### Tab management + +* **Search, drag and drop, and renaming** - Filter panes by title, directory, or branch; reorder tabs or move panes between tabs by dragging; double-click a tab to rename it inline. +* **New tab menu** - Create agent tabs, terminal tabs, Oz cloud agent sessions, worktree configs, and [Tab Configs](/terminal/windows/tab-configs/) from a unified **+** menu. + +## Enabling vertical tabs + +To switch from horizontal tabs to the vertical tabs panel: + +1. In the Warp app, navigate to **Settings** > **Appearance** > **Tabs**. +2. Toggle **Use vertical tab layout** on. + +The vertical tabs panel appears as a resizable sidebar on the left side of the window. The horizontal tab bar is hidden while vertical tabs are active. + +![A Warp window with the vertical tabs sidebar on the left listing a Claude Code tab and a codex tab alongside the main terminal pane](../../../../assets/terminal/multi-agents.png) + +:::note +You can also toggle vertical tabs from the [Command Palette](/terminal/command-palette/) by searching for "vertical tab layout." +::: + +## View modes + +The vertical tabs panel supports two display densities that you can switch between at any time. + +### Compact mode + +Compact mode is the default. Each pane row displays an icon and title on one line, with an optional subtitle below it. The subtitle is configurable via the **Additional metadata** setting in the settings popup. + +![Vertical tabs sidebar in compact mode with each pane row showing an icon, title, and a short subtitle below](../../../../assets/terminal/vertical-tabs-condensed.png) + +### Expanded mode + +Expanded mode shows each pane row with a title, description (such as the working directory or file path), and metadata (Git branch, diff stats badge, and PR badge when available). + +![Vertical tab rows in expanded mode showing titles, working directories, Git branches, diff stats, and agent status badges](../../../../assets/terminal/vertical-tabs-multi-agent.png) + +### Switching view modes + +Click the settings icon (sliders) in the control bar at the top of the vertical tabs panel. In the popup, use the **Density** segmented control to switch between compact and expanded views. The change takes effect immediately. + +![The vertical tabs settings popup anchored to the sliders icon, showing View as, Density, Pane title as, Additional metadata, and Show details on hover options](../../../../assets/terminal/vertical-tab-settings.png) + +## Customizing vertical tabs + +When vertical tabs are enabled, configure their appearance and behavior from the settings popup (click the sliders icon in the control bar) or from **Settings** > **Appearance** > **Tabs**. + +You can also rearrange the panel toggle buttons at the top of the Warp window — including the tabs panel, tools panel, agent management, code review, and notifications mailbox — and move them between the left and right sides of the header. See [Configurable toolbar](/terminal/windows/configurable-toolbar/) for details. + +| Setting | Availability | Options | Default | +|---|---|---|---| +| **View as** | Always | **Panes** — each split pane gets its own row. **Tabs** — only the focused pane per tab is shown. | Panes | +| **Density** | Always | **Compact** — smaller rows with title and optional subtitle. **Expanded** — larger rows with title, description, and metadata. | Compact | +| **Pane title as** | Always | **Command / Conversation** — last command, conversation title, or CLI agent session name.<br />**Working Directory** — pane's working directory.<br />**Branch** — checked-out Git branch. | Command / Conversation | +| **Additional metadata** | Compact mode only | **Branch**<br />**Working Directory**<br />**Command / Conversation**<br />(options depend on the **Pane title as** setting; duplicates are excluded). | Branch | +| **Show** | Expanded mode only | **PR link** — pull request and status for the current branch (requires GitHub CLI). **Diff stats** — lines added/removed. | — | +| **Show details on hover** | Always | On / Off — toggles the hover detail sidecar. | On | + +### Automatic metadata + +The following metadata appears automatically and doesn't require configuration: + +* **Git branch** - The currently checked-out branch for the pane's working directory. +* **Worktree** - The active [Git worktree](/code/git-worktrees/) path, if applicable. +* **Agent status** - A colored badge on the pane icon indicating the agent's current state (see [Agent status badges](#agent-status-badges) below). +* **Notification dot** - An accent-colored dot on the title row when a pane has unread agent activity. + +## Agent status badges + +Agent pane icons display a small circular badge overlay in the bottom-right corner that reflects the agent's current state: + +| Status | Icon | Meaning | +|---|---|---| +| **In progress** | Magenta clock | The agent is actively running. | +| **Done** | Green check | The agent's last turn completed successfully. | +| **Error** | Red triangle | The agent's last turn completed with an error. | +| **Cancelled** | Gray stop | The user cancelled the agent's last turn. | +| **Blocked** | Yellow stop | The agent is waiting for user approval to proceed. | + +![Vertical tabs sidebar with four tab rows showing different agent status badges: a yellow blocked square, a magenta in-progress moon on the Claude Code brand icon, and green completion checks](../../../../assets/terminal/agent-status-badges.png) + +Third-party CLI agents (Claude Code, Codex, Gemini CLI, and others) display their brand icon and color inside the circular pane icon, with the same status badge overlay. + +When a pane has unread agent activity, an accent-colored notification dot appears at the right edge of the title row. The dot clears when you focus the pane. + +## Managing tabs + +### Search + +The control bar at the top of the vertical tabs panel includes a search field. Type to filter the visible tabs and panes by title, working directory, Git branch, PR label, or diff stats. Only matching tabs remain visible while the search query is active. + +### New tab menu + +Click the **+** button in the control bar to open the new tab menu. The menu includes: + +* **Agent** - Open a new agent tab. +* **Terminal** - Open a new terminal tab. +* **Oz cloud agent** - Open a new Oz cloud agent session tab. +* **Tab Configs** - Any [Tab Configs](/terminal/windows/tab-configs/) you've created appear as menu items for one-click setup. +* **New worktree config** - Create a new worktree-based Tab Config. +* **New tab config** - Create a new Tab Config from a starter template. + +### Drag and drop + +Reorder tabs by dragging tab group headers within the panel. To move a pane from one tab to another, drag the pane header over a different tab group in the panel. Warp switches to that tab so you can place the pane using the standard drop targets. Dropping a pane between tab groups creates a new tab at that position. + +### Tab renaming + +Double-click a tab row to rename it inline. Press `Enter` to confirm or `Esc` to cancel. + +:::note +Renaming applies to tabs only. Individual panes can't be renamed at this time. +::: + +## Hover detail sidecar + +Hover any pane row to open a floating detail card anchored to the right side of the panel. The sidecar shows full, un-clipped metadata (complete directory paths, full branch names, and the full conversation or command title) without changing which pane is focused. + +![The vertical tabs panel with a Claude Code tab hovered, showing a floating detail card with the agent's In progress status, working directory, and session title](../../../../assets/terminal/tab-hover-detail-card.png) + +The sidecar stays open as you move the cursor from the row into the card. Move away from both the row and the sidecar to dismiss it. Disable this behavior with the **Show details on hover** toggle in the settings popup. + +## Keyboard shortcuts + +All existing tab keyboard shortcuts continue to work with vertical tabs. The sidebar layout changes how tabs are displayed, not how you interact with them. See [Terminal tabs](/terminal/windows/tabs/) for the full list of tab shortcuts. + +## Related pages + +* [Terminal tabs](/terminal/windows/tabs/) - Horizontal tab bar usage and keyboard shortcuts +* [Split panes](/terminal/windows/split-panes/) - Divide tabs into multiple terminal panes +* [Tab Configs](/terminal/windows/tab-configs/) - Define reusable tab setups in TOML files +* [Git Worktrees](/code/git-worktrees/) - Worktree support that surfaces in vertical tab metadata +* [Tabs behavior](/terminal/appearance/tabs-behavior/) - Tab bar visibility, indicators, and close button settings +* [Third-party CLI agents](/agent-platform/cli-agents/overview/) - Use Claude Code, Codex, Gemini CLI, and other third-party agents with Warp's utility bar, including brand icons and status badges in the vertical tabs panel diff --git a/src/env.d.ts b/src/env.d.ts new file mode 100644 index 0000000..7c47989 --- /dev/null +++ b/src/env.d.ts @@ -0,0 +1,41 @@ +/// <reference path="../.astro/types.d.ts" /> + +// Starlight resolves these at build time via Vite virtual modules so it can +// hand a *Starlight-aware* version of each component to overrides like +// `CustomPageSidebar.astro` and `FeedbackFooter.astro`. They have no runtime +// `.d.ts` shipped from `@astrojs/starlight`, so we declare them here as +// `*.astro` modules to keep `astro check` clean. +declare module 'virtual:starlight/components/Pagination' { + const Component: typeof import('astro').AstroComponentFactory; + export default Component; +} + +declare module 'virtual:starlight/components/TableOfContents' { + const Component: typeof import('astro').AstroComponentFactory; + export default Component; +} + +declare module 'virtual:starlight/components/MobileTableOfContents' { + const Component: typeof import('astro').AstroComponentFactory; + export default Component; +} + +declare module 'virtual:starlight/components/SiteTitle' { + const Component: typeof import('astro').AstroComponentFactory; + export default Component; +} + +declare module 'virtual:starlight/components/SocialIcons' { + const Component: typeof import('astro').AstroComponentFactory; + export default Component; +} + +declare module 'virtual:starlight/components/ThemeSelect' { + const Component: typeof import('astro').AstroComponentFactory; + export default Component; +} + +declare module 'virtual:starlight/components/LanguageSelect' { + const Component: typeof import('astro').AstroComponentFactory; + export default Component; +} diff --git a/src/integrations/docs-markdown-integration.js b/src/integrations/docs-markdown-integration.js new file mode 100644 index 0000000..81ce540 --- /dev/null +++ b/src/integrations/docs-markdown-integration.js @@ -0,0 +1,166 @@ +import { mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { parseHTML } from 'linkedom'; +import TurndownService from 'turndown'; +import { gfm } from 'turndown-plugin-gfm'; + +export default function docsMarkdownIntegration() { + return { + name: 'warp-docs-markdown', + hooks: { + 'astro:build:generated': async ({ dir, logger }) => { + const outputRoot = fileURLToPath(dir); + const markdownCount = await generateMarkdownFiles(outputRoot); + logger.info(`Generated ${markdownCount} Markdown docs`); + }, + }, + }; +} + +const turndown = createMarkdownConverter(); + +async function generateMarkdownFiles(outputRoot) { + const htmlFiles = await collectHtmlFiles(outputRoot, readdir); + let markdownCount = 0; + + for (const htmlFile of htmlFiles) { + const relativeHtmlPath = path.relative(outputRoot, htmlFile); + if (!isDocHtmlFile(relativeHtmlPath)) continue; + + const markdownPath = getMarkdownOutputPath(outputRoot, relativeHtmlPath); + const html = await readFile(htmlFile, 'utf8'); + const markdown = convertHtmlToMarkdown(html); + if (!markdown) continue; + + await mkdir(path.dirname(markdownPath), { recursive: true }); + await writeFile(markdownPath, markdown, 'utf8'); + await rm(`${markdownPath}.html`, { force: true }); + markdownCount += 1; + } + + return markdownCount; +} + +async function collectHtmlFiles(rootDir, readdir) { + /** @type {string[]} */ + const htmlFiles = []; + + async function walk(currentDir) { + const entries = await readdir(currentDir, { withFileTypes: true }); + for (const entry of entries) { + const entryPath = path.join(currentDir, entry.name); + if (entry.isDirectory()) { + await walk(entryPath); + continue; + } + if (entry.isFile() && entry.name.endsWith('.html')) { + htmlFiles.push(entryPath); + } + } + } + + await walk(rootDir); + return htmlFiles; +} + +function isDocHtmlFile(relativeHtmlPath) { + if (relativeHtmlPath === '404.html') return false; + return relativeHtmlPath === 'index.html' || relativeHtmlPath.endsWith('/index.html'); +} + +function getMarkdownOutputPath(outputRoot, relativeHtmlPath) { + if (relativeHtmlPath === 'index.html') { + return path.join(outputRoot, 'index.md'); + } + + const htmlDir = path.dirname(relativeHtmlPath); + return path.join(outputRoot, `${htmlDir}.md`); +} + +function convertHtmlToMarkdown(html) { + const { document } = parseHTML(html); + const title = document.querySelector('h1[data-page-title], main h1')?.textContent?.trim(); + const description = document.querySelector('meta[name="description"]')?.getAttribute('content')?.trim(); + const contentRoot = document.querySelector('main .sl-markdown-content'); + if (!title || !contentRoot) return ''; + + const clone = /** @type {HTMLElement} */ (contentRoot.cloneNode(true)); + sanitizeRoot(clone); + const markdownBody = turndown.turndown(clone.innerHTML).trim(); + const sections = [`# ${normalizeWhitespace(title)}`]; + + if (description) { + sections.push(description); + } + + if (markdownBody) { + sections.push(markdownBody); + } + + return `${sections.join('\n\n').trim()}\n`; +} + +function sanitizeRoot(root) { + for (const selector of [ + 'script', + 'style', + 'noscript', + '.sl-anchor-link', + '.expressive-code .copy', + '.sr-only', + '[data-pagefind-ignore]', + ]) { + root.querySelectorAll(selector).forEach((node) => node.remove()); + } +} + +function createMarkdownConverter() { + const service = new TurndownService({ + headingStyle: 'atx', + codeBlockStyle: 'fenced', + bulletListMarker: '-', + emDelimiter: '*', + strongDelimiter: '**', + }); + + service.use(gfm); + + service.addRule('expressiveCodeBlock', { + filter: (node) => isElement(node) && node.classList.contains('expressive-code'), + replacement(_content, node) { + if (!isElement(node)) return '\n\n'; + + const code = node.querySelector('pre code'); + if (!code) return '\n\n'; + + const language = + code.getAttribute('data-language') ?? code.className.match(/language-([\w-]+)/)?.[1] ?? ''; + const rawCode = normalizeNewlines(code.textContent ?? '').replace(/\n$/, ''); + const fence = getFence(rawCode); + const openingFence = language ? `${fence}${language}` : fence; + + return `\n\n${openingFence}\n${rawCode}\n${fence}\n\n`; + }, + }); + + return service; +} + +function isElement(node) { + return node.nodeType === 1; +} + +function getFence(code) { + const matches = code.match(/`+/g) ?? ['']; + const maxBackticks = Math.max(...matches.map((value) => value.length)); + return '`'.repeat(Math.max(3, maxBackticks + 1)); +} + +function normalizeNewlines(text) { + return text.replace(/\r\n?/g, '\n'); +} + +function normalizeWhitespace(text) { + return text.replace(/\s+/g, ' ').trim(); +} diff --git a/src/lib/docs-markdown.js b/src/lib/docs-markdown.js new file mode 100644 index 0000000..689480e --- /dev/null +++ b/src/lib/docs-markdown.js @@ -0,0 +1,53 @@ +const AGENT_USER_AGENT_TOKENS = [ + 'chatgpt', + 'claude', + 'anthropic', + 'openai', + 'cursor', + 'perplexity', + 'windsurf', + 'cline', +]; + +/** + * @param {string} pathname + */ +export function getMarkdownPathFromHtmlPath(pathname) { + const normalizedPath = normalizePathname(pathname); + if (normalizedPath === '/') return '/index.md'; + return `${normalizedPath}.md`; +} + +/** + * @param {string} pathname + */ +export function isEligibleDocHtmlPath(pathname) { + const normalizedPath = normalizePathname(pathname); + if (normalizedPath === '/') return true; + if (normalizedPath.startsWith('/_astro/')) return false; + const lastSegment = normalizedPath.split('/').at(-1) ?? ''; + return lastSegment.length > 0 && !lastSegment.includes('.'); +} + +/** + * Prefer explicit content negotiation and keep user-agent matching as a + * compatibility fallback for tools that do not send a markdown-specific + * Accept header. + * + * @param {Request} request + */ +export function shouldServeMarkdown(request) { + const accept = request.headers.get('accept')?.toLowerCase() ?? ''; + if (accept.includes('text/markdown') || accept.includes('text/plain')) { + return true; + } + + const userAgent = request.headers.get('user-agent')?.toLowerCase() ?? ''; + return AGENT_USER_AGENT_TOKENS.some((token) => userAgent.includes(token)); +} + +function normalizePathname(pathname) { + if (!pathname || pathname === '/') return '/'; + const trimmedPath = pathname.replace(/\/+$/, ''); + return trimmedPath || '/'; +} diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 0000000..40c7dad --- /dev/null +++ b/src/middleware.ts @@ -0,0 +1,26 @@ +import { defineMiddleware } from 'astro:middleware'; +import { + getMarkdownPathFromHtmlPath, + isEligibleDocHtmlPath, + shouldServeMarkdown, +} from './lib/docs-markdown.js'; + +export const onRequest = defineMiddleware((context, next) => { + if (!['GET', 'HEAD'].includes(context.request.method)) { + return next(); + } + + if (!isEligibleDocHtmlPath(context.url.pathname)) { + return next(); + } + + // Content negotiation for AI agents — only needed at runtime. + // Skip during prerendering (both dev and build) to avoid + // Astro.request.headers warnings on every static page. + if (context.isPrerendered || !shouldServeMarkdown(context.request)) { + return next(); + } + + const markdownUrl = new URL(getMarkdownPathFromHtmlPath(context.url.pathname), context.url); + return next(markdownUrl); +}); diff --git a/src/pages/[...slug].md.ts b/src/pages/[...slug].md.ts new file mode 100644 index 0000000..4bbd38e --- /dev/null +++ b/src/pages/[...slug].md.ts @@ -0,0 +1,58 @@ +import type { APIRoute } from 'astro'; +import { getCollection } from 'astro:content'; + +/** + * Serves the raw MDX body of any doc page at `<url>.md`. + * + * / → /index.md + * /quickstart/ → /quickstart.md + * /terminal/blocks/ → /terminal/blocks.md + * /terminal/command-palette/ → /terminal/command-palette.md + * + * In dev, Astro routes `.md` requests to this endpoint. In production + * builds, prerendering writes the `.md` files to disk; the existing + * `docs-markdown-integration` then overwrites them with its turndown + * output (which produces cleaner markdown from the rendered HTML). + */ +export async function getStaticPaths() { + const entries = await getCollection('docs'); + return entries.map((entry) => { + let slug: string; + if (entry.id === 'index') { + slug = 'index'; + } else if (entry.id.endsWith('/index')) { + slug = entry.id.slice(0, -'/index'.length); + } else { + slug = entry.id; + } + return { + params: { slug }, + props: { entry }, + }; + }); +} + +export const GET: APIRoute = ({ props }) => { + const entry = props.entry as { + id: string; + body?: string; + data: { title?: string; description?: string }; + }; + + const title = entry.data.title ?? ''; + const description = entry.data.description ?? ''; + const body = entry.body ?? ''; + + const sections = []; + if (title) sections.push(`# ${title}`); + if (description) sections.push(description); + if (body) sections.push(body); + + return new Response(`${sections.join('\n\n').trim()}\n`, { + status: 200, + headers: { + 'Content-Type': 'text/markdown; charset=utf-8', + 'Cache-Control': 'public, max-age=0, must-revalidate', + }, + }); +}; diff --git a/src/pages/api.astro b/src/pages/api.astro new file mode 100644 index 0000000..c56f5da --- /dev/null +++ b/src/pages/api.astro @@ -0,0 +1,364 @@ +--- +// Standalone Scalar API reference — not embedded in Starlight. +// Accessible at docs.warp.dev/api +// Spec lives at `developers/agent-api-openapi.yaml`, synced from the +// upstream Oz Agent API source. Re-sync that file when the API changes +// and this page picks it up at the next build. +// +// Note on `set:html={specJson}` below: the injected value is JSON.stringify() +// of a YAML file that lives in this repo and is read at build time. It is not +// user input, so injecting it into a <script type="application/json"> element +// is safe. JSON.stringify also escapes `</script>` sequences to keep the +// script tag well-formed. +import fs from 'node:fs'; +import { parse } from 'yaml'; +import WarpTopbar from '../components/WarpTopbar.astro'; +import FeedbackButtons from '../components/FeedbackButtons.astro'; +const yamlContent = fs.readFileSync('developers/agent-api-openapi.yaml', 'utf-8'); +const specObject = parse(yamlContent); +const specJson = JSON.stringify(specObject); +// `PUBLIC_PUSHFEEDBACK_PROJECT_ID` is read directly inside `<FeedbackButtons />` +// (see `src/components/FeedbackButtons.astro`) — no need to plumb it through +// here. +--- + +<!doctype html> +<html lang="en"> + <head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <title>Oz Agent API Reference | Warp + + + + + + + + + + + + + + + + + + + + {/* PushFeedback CSS + JS are NOT loaded here — the lazy loader inside + `` (rendered below) injects them on idle so the + Scalar reference's first paint isn't blocked on a CDN fetch. */} + + + + + + + + + + diff --git a/src/pages/changelog/rss.xml.ts b/src/pages/changelog/rss.xml.ts new file mode 100644 index 0000000..3984cd5 --- /dev/null +++ b/src/pages/changelog/rss.xml.ts @@ -0,0 +1,93 @@ +import rss from '@astrojs/rss'; +import type { APIContext } from 'astro'; +import { getEntry } from 'astro:content'; + +/** + * RSS feed for the Warp changelog. + * + * The legacy GitBook docs auto-generated `/changelog/rss.xml` and + * `vercel.json` already redirects a handful of legacy paths + * (`/changelog/changelog/rss`, `/changelog/rss`, etc.) to `/changelog/`. + * We restore the canonical feed at `/changelog/rss.xml` so existing + * subscribers (and any external links) keep working. + * + * The changelog is a single MDX file with H3 headings of the form + * `### YYYY.MM.DD (vX.Y...)`. We split on those headings so each + * release becomes its own RSS item with a stable pubDate. + */ +const RELEASE_HEADING = /^###\s+(\d{4})\.(\d{2})\.(\d{2})(?:\s*\(([^)]*)\))?\s*$/m; + +interface ReleaseSection { + title: string; + pubDate: Date; + body: string; +} + +function splitReleases(body: string): ReleaseSection[] { + const lines = body.split('\n'); + const releases: ReleaseSection[] = []; + let current: { headerMatch: RegExpMatchArray; lines: string[] } | null = null; + + for (const line of lines) { + const match = line.match(RELEASE_HEADING); + if (match) { + if (current) { + releases.push(buildRelease(current)); + } + current = { headerMatch: match, lines: [] }; + continue; + } + if (current) { + current.lines.push(line); + } + } + if (current) { + releases.push(buildRelease(current)); + } + return releases; +} + +function buildRelease({ + headerMatch, + lines, +}: { + headerMatch: RegExpMatchArray; + lines: string[]; +}): ReleaseSection { + const [, year, month, day, version] = headerMatch; + const date = `${year}.${month}.${day}`; + const title = version ? `${date} (${version})` : date; + // Use noon UTC so the ordering is stable regardless of the reader's TZ. + const pubDate = new Date(`${year}-${month}-${day}T12:00:00Z`); + return { title, pubDate, body: lines.join('\n').trim() }; +} + +export async function GET(context: APIContext) { + const entry = await getEntry('docs', 'changelog'); + if (!entry) { + return new Response('Changelog not found', { status: 404 }); + } + + const releases = splitReleases(entry.body ?? ''); + const site = context.site ?? new URL('https://docs.warp.dev'); + const channelLink = new URL('/changelog/', site).href; + + return rss({ + title: 'Warp Changelog', + description: + entry.data.description ?? + 'Updates and release notes for Warp, the Agentic Development Environment.', + site, + items: releases.map((release) => ({ + title: release.title, + pubDate: release.pubDate, + // Anchor each item to the corresponding release on the changelog page. + link: `${channelLink}#${release.title + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/^-|-$/g, '')}`, + description: release.body, + })), + customData: 'en-us', + }); +} diff --git a/src/plugins/page-title-override.ts b/src/plugins/page-title-override.ts new file mode 100644 index 0000000..2732d43 --- /dev/null +++ b/src/plugins/page-title-override.ts @@ -0,0 +1,26 @@ +import type { StarlightPlugin } from '@astrojs/starlight/types'; + +/** + * Re-applies the custom PageTitle override after other plugins + * (like starlight-sidebar-topics) have run. + * + * Starlight's `updateConfig` shallow-merges at the top level — passing + * `{ components: { PageTitle } }` would wipe out Head, Search, Footer, + * and Sidebar overrides that earlier plugins/user config set. So we + * spread `config.components` first to preserve everything. + */ +export default function pageTitleOverride(): StarlightPlugin { + return { + name: 'page-title-override', + hooks: { + 'config:setup'({ config, updateConfig }) { + updateConfig({ + components: { + ...config.components, + PageTitle: './src/components/CustomPageTitle.astro', + }, + }); + }, + }, + }; +} diff --git a/src/routeData.ts b/src/routeData.ts new file mode 100644 index 0000000..f5fc833 --- /dev/null +++ b/src/routeData.ts @@ -0,0 +1,65 @@ +import { defineRouteMiddleware } from '@astrojs/starlight/route-data'; +import config from 'virtual:starlight/user-config'; +import { getMarkdownPathFromHtmlPath } from './lib/docs-markdown.js'; + +/** + * Per-page head augmentation. + * + * - Always exposes the page's Markdown source via `` + * (matches what GitBook serves today and what AI agents look for). + * - Pushes branded OG and Twitter tags so social previews include the site + * name ("Page Title | Warp") and a real preview image. Starlight's + * `getHead()` runs before this middleware and seeds `route.head` with its + * defaults; we strip its bare `og:title` first so we don't end up with + * duplicate tags, then push the branded replacement. + */ +export const onRequest = defineRouteMiddleware((context) => { + const route = context.locals.starlightRoute; + const head = route.head; + + head.push({ + tag: 'link', + attrs: { + rel: 'alternate', + type: 'text/markdown', + href: getMarkdownPathFromHtmlPath(context.url.pathname), + }, + }); + + const siteTitle = + (typeof config.title === 'string' ? config.title : config.title?.en) ?? 'Warp'; + const pageTitle = route.entry?.data?.title ?? siteTitle; + const pageDescription = route.entry?.data?.description ?? config.description; + const brandedTitle = `${pageTitle} ${config.titleDelimiter} ${siteTitle}`; + const site = context.site ?? new URL('https://docs.warp.dev'); + const ogImageUrl = new URL('/og-image.png', site).href; + + // Drop Starlight's bare og:title before adding the branded one. Inline + // rather than a helper so we keep the exact `route.head` element type + // (Starlight types `attrs` values as `string | boolean | undefined`, + // which a separate function signature would have to restate). + for (let i = head.length - 1; i >= 0; i--) { + const entry = head[i]; + if (entry.tag === 'meta' && entry.attrs?.property === 'og:title') { + head.splice(i, 1); + } + } + + head.push( + { tag: 'meta', attrs: { property: 'og:title', content: brandedTitle } }, + { tag: 'meta', attrs: { property: 'og:image', content: ogImageUrl } }, + { tag: 'meta', attrs: { property: 'og:image:secure_url', content: ogImageUrl } }, + { tag: 'meta', attrs: { property: 'og:image:type', content: 'image/png' } }, + { tag: 'meta', attrs: { property: 'og:image:width', content: '1200' } }, + { tag: 'meta', attrs: { property: 'og:image:height', content: '630' } }, + { tag: 'meta', attrs: { property: 'og:image:alt', content: `${siteTitle} — ${pageTitle}` } }, + { tag: 'meta', attrs: { name: 'twitter:title', content: brandedTitle } }, + { tag: 'meta', attrs: { name: 'twitter:image', content: ogImageUrl } }, + ); + if (pageDescription) { + head.push({ + tag: 'meta', + attrs: { name: 'twitter:description', content: pageDescription }, + }); + } +}); diff --git a/src/sidebar.ts b/src/sidebar.ts new file mode 100644 index 0000000..63ea8fe --- /dev/null +++ b/src/sidebar.ts @@ -0,0 +1,634 @@ +import type { StarlightSidebarTopicsUserConfig } from 'starlight-sidebar-topics'; + +/** + * Top-level sidebar topics, one per "tab" the docs site exposes. + * + * `starlight-sidebar-topics` reads this array and renders each entry as a + * pill in the header + a sidebar tree below. Slugs are relative to + * `src/content/docs/`. Object form (`{ slug, label }`) lets us override + * the link label without renaming the underlying MDX file. + * + * Lifted out of `astro.config.mjs` so content reorgs land here instead of + * lengthening the integration config — `git blame` on a moved page now + * points at this file. + * + * Item order and section grouping follows the source GitBook SUMMARY.md + * files in ~/Projects/gitbook so the migrated site preserves the original + * navigation structure. + */ +export const sidebarTopics: StarlightSidebarTopicsUserConfig = [ + { + label: 'Terminal', + link: '/', + icon: 'laptop', + items: [ + { + label: 'Getting started', + items: [ + { label: 'Getting started with Warp and Oz', link: '/' }, + { slug: 'quickstart', label: 'Warp quickstart' }, + 'getting-started/quickstart/installation-and-setup', + 'getting-started/quickstart/coding-in-warp', + 'getting-started/quickstart/customizing-warp', + { + label: 'Migrate to Warp', + items: [ + { slug: 'getting-started/migrate-to-warp', label: 'Overview' }, + 'getting-started/migrate-to-warp/migrate-to-warp-from-claude-code', + 'getting-started/migrate-to-warp/migrate-to-warp-from-cursor', + 'getting-started/migrate-to-warp/migrate-to-warp-from-ghostty', + 'getting-started/migrate-to-warp/migrate-to-warp-from-iterm2', + 'getting-started/migrate-to-warp/migrate-to-warp-from-macos-terminal', + 'getting-started/migrate-to-warp/migrate-to-warp-from-vs-code-terminal', + 'getting-started/migrate-to-warp/migrate-to-warp-from-windows-terminal', + ], + }, + { slug: 'getting-started/supported-shells', label: 'Supported shells' }, + { slug: 'getting-started/keyboard-shortcuts', label: 'Keyboard shortcuts' }, + ], + }, + { + label: 'Terminal', + items: [ + 'terminal/input/universal-input', + 'terminal/input/classic-input', + { + label: 'Blocks', + items: [ + { slug: 'terminal/blocks', label: 'Overview' }, + { slug: 'terminal/blocks/block-basics', label: 'Block basics' }, + { slug: 'terminal/blocks/block-actions', label: 'Block actions' }, + { slug: 'terminal/blocks/block-sharing', label: 'Block sharing' }, + { slug: 'terminal/blocks/find', label: 'Block find' }, + { slug: 'terminal/blocks/block-filtering', label: 'Block filtering' }, + { slug: 'terminal/blocks/background-blocks', label: 'Background blocks' }, + 'terminal/blocks/sticky-command-header', + ], + }, + { + label: 'Modern text editing', + items: [ + { slug: 'terminal/editor', label: 'Overview' }, + { slug: 'terminal/editor/alias-expansion', label: 'Alias expansion' }, + { slug: 'terminal/editor/command-inspector', label: 'Command inspector' }, + { slug: 'terminal/editor/syntax-error-highlighting', label: 'Syntax & error highlighting' }, + { slug: 'terminal/editor/vim', label: 'Vim keybindings' }, + ], + }, + { + label: 'Command entry', + items: [ + { slug: 'terminal/entry', label: 'Overview' }, + { slug: 'terminal/entry/command-corrections', label: 'Command corrections' }, + { slug: 'terminal/entry/command-search', label: 'Command search' }, + { slug: 'terminal/entry/command-history', label: 'Command history' }, + { slug: 'terminal/entry/synchronized-inputs', label: 'Synchronized inputs' }, + { slug: 'terminal/entry/yaml-workflows', label: 'YAML workflows' }, + ], + }, + { + label: 'Command completions', + items: [ + { slug: 'terminal/command-completions', label: 'Overview' }, + { slug: 'terminal/command-completions/completions', label: 'Tab completions' }, + 'terminal/command-completions/autosuggestions', + ], + }, + { + label: 'Windows and Tabs', + items: [ + { slug: 'terminal/windows', label: 'Overview' }, + 'terminal/windows/tabs', + { slug: 'terminal/windows/vertical-tabs', label: 'Vertical Tabs' }, + 'terminal/windows/split-panes', + 'terminal/windows/tab-configs', + 'terminal/windows/configurable-toolbar', + { slug: 'terminal/windows/global-hotkey', label: 'Global hotkey' }, + { slug: 'terminal/sessions/launch-configurations', label: 'Launch Configurations (Legacy)' }, + ], + }, + { + label: 'Sessions', + items: [ + { slug: 'terminal/sessions', label: 'Overview' }, + { slug: 'terminal/sessions/session-navigation', label: 'Session navigation' }, + { slug: 'terminal/sessions/session-restoration', label: 'Session restoration' }, + ], + }, + { + label: 'Terminal appearance', + items: [ + { slug: 'terminal/appearance', label: 'Overview' }, + { slug: 'terminal/appearance/themes', label: 'Themes' }, + { slug: 'terminal/appearance/custom-themes', label: 'Custom themes' }, + { slug: 'terminal/appearance/prompt', label: 'Prompt' }, + 'terminal/appearance/input-position', + { slug: 'terminal/appearance/text-fonts-cursor', label: 'Text, fonts, & cursor' }, + { slug: 'terminal/appearance/size-opacity-blurring', label: 'Size, opacity, & blurring' }, + { slug: 'terminal/appearance/pane-dimming', label: 'Pane dimming & focus' }, + { slug: 'terminal/appearance/blocks-behavior', label: 'Blocks behavior' }, + { slug: 'terminal/appearance/tabs-behavior', label: 'Tabs behavior' }, + { slug: 'terminal/appearance/app-icons', label: 'Custom app icons' }, + ], + }, + { + label: 'Settings file', + items: [ + { slug: 'terminal/settings', label: 'Overview' }, + { slug: 'terminal/settings/all-settings', label: 'All settings reference' }, + ], + }, + { + label: 'Warpify overview', + items: [ + { slug: 'terminal/warpify', label: 'Overview' }, + { slug: 'terminal/warpify/subshells', label: 'Warpify subshells' }, + { slug: 'terminal/warpify/ssh', label: 'SSH with Warp features' }, + { slug: 'terminal/warpify/ssh-legacy', label: 'Legacy SSH wrapper' }, + ], + }, + { + label: 'More Features', + items: [ + { slug: 'terminal/more-features', label: 'Overview' }, + 'terminal/more-features/accessibility', + { slug: 'terminal/more-features/files-and-links', label: 'Files, links, & scripts' }, + { slug: 'terminal/more-features/markdown-viewer', label: 'Markdown viewer' }, + { slug: 'terminal/more-features/working-directory', label: 'Working directory' }, + 'terminal/more-features/text-selection', + 'terminal/more-features/full-screen-apps', + { slug: 'terminal/more-features/notifications', label: 'Desktop notifications' }, + { slug: 'terminal/more-features/audible-bell', label: 'Audible terminal bell' }, + { slug: 'terminal/more-features/settings-sync', label: 'Settings Sync (Beta)' }, + { slug: 'terminal/more-features/quit-warning', label: 'Terminal quit warning' }, + { slug: 'terminal/more-features/uri-scheme', label: 'Warp URI scheme' }, + { slug: 'terminal/more-features/linux', label: 'Warp for Linux' }, + ], + }, + 'terminal/command-palette', + { + label: 'Terminal comparisons', + items: [ + { slug: 'terminal/comparisons', label: 'Overview' }, + { slug: 'terminal/comparisons/performance', label: 'Performance benchmarks' }, + ], + }, + { slug: 'terminal/comparisons/terminal-features', label: 'Terminal features' }, + { slug: 'terminal/integrations-and-plugins', label: 'Terminal integrations' }, + ], + }, + { + label: 'Code', + items: [ + { slug: 'code/overview', label: 'Code overview' }, + { + label: 'Built-in code editor', + items: [ + { slug: 'code/code-editor', label: 'Overview' }, + { slug: 'code/code-editor/language-server-protocol', label: 'Language Server Protocol (LSP)' }, + { slug: 'code/code-editor/file-tree', label: 'File Tree (Project Explorer)' }, + { slug: 'code/code-editor/find-and-replace', label: 'Find & replace' }, + { slug: 'code/code-editor/code-editor-vim-keybindings', label: 'Code editor Vim keybindings' }, + ], + }, + { slug: 'code/code-review', label: 'Code Review panel' }, + { slug: 'code/git-worktrees', label: 'Git Worktrees' }, + { slug: 'code/ssh-feature-support', label: 'Feature support over SSH' }, + ], + }, + { + label: 'Knowledge and collaboration', + items: [ + { + label: 'Warp Drive overview', + items: [ + { slug: 'knowledge-and-collaboration/warp-drive', label: 'Overview' }, + { slug: 'knowledge-and-collaboration/warp-drive/notebooks', label: 'Notebooks' }, + { slug: 'knowledge-and-collaboration/warp-drive/workflows', label: 'Workflows' }, + { slug: 'knowledge-and-collaboration/warp-drive/prompts', label: 'Prompts' }, + 'knowledge-and-collaboration/warp-drive/environment-variables', + { slug: 'knowledge-and-collaboration/warp-drive/ai-objects', label: 'AI-Integrated Objects' }, + { slug: 'knowledge-and-collaboration/warp-drive/web', label: 'Warp Drive on the web' }, + { slug: 'knowledge-and-collaboration/warp-drive/agent-mode-context', label: 'Agent Mode context' }, + ], + }, + { slug: 'knowledge-and-collaboration/teams', label: 'Team management' }, + { slug: 'knowledge-and-collaboration/admin-panel', label: 'Team Admin Panel' }, + { slug: 'knowledge-and-collaboration/session-sharing', label: 'Session sharing' }, + ], + }, + ], + }, + { + label: 'Agents', + link: '/agent-platform/', + icon: 'puzzle', + items: [ + { + label: 'Getting started', + items: [ + { slug: 'agent-platform', label: 'Agents overview' }, + 'agent-platform/getting-started/agents-in-warp', + 'agent-platform/getting-started/faqs', + ], + }, + { + label: 'Warp Agents', + items: [ + { slug: 'agent-platform/local-agents/overview', label: 'Warp Agents overview' }, + { + label: 'Capabilities', + items: [ + { slug: 'agent-platform/capabilities', label: 'Overview' }, + { slug: 'agent-platform/capabilities/slash-commands', label: 'Slash commands' }, + 'agent-platform/capabilities/skills', + 'agent-platform/capabilities/planning', + { slug: 'agent-platform/capabilities/task-lists', label: 'Task lists' }, + 'agent-platform/capabilities/model-choice', + 'agent-platform/capabilities/rules', + { slug: 'agent-platform/capabilities/agent-notifications', label: 'Agent notifications' }, + { slug: 'agent-platform/capabilities/full-terminal-use', label: 'Full terminal use' }, + { slug: 'agent-platform/capabilities/computer-use', label: 'Computer use' }, + 'agent-platform/capabilities/codebase-context', + { slug: 'agent-platform/capabilities/agent-profiles-permissions', label: 'Profiles & permissions' }, + { slug: 'agent-platform/capabilities/web-search', label: 'Web search' }, + { slug: 'agent-platform/local-agents/session-sharing', label: 'Session sharing' }, + 'agent-platform/local-agents/cloud-conversations', + ], + }, + { + label: 'Interacting with agents', + items: [ + { slug: 'agent-platform/local-agents/interacting-with-agents', label: 'Overview' }, + 'agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes', + { slug: 'agent-platform/local-agents/interacting-with-agents/conversation-forking', label: 'Conversation forking' }, + { slug: 'agent-platform/local-agents/code-diffs', label: 'Code diffs' }, + 'agent-platform/local-agents/interacting-with-agents/voice', + ], + }, + { + label: 'Agent context', + items: [ + { slug: 'agent-platform/local-agents/agent-context', label: 'Overview' }, + { slug: 'agent-platform/local-agents/agent-context/blocks-as-context', label: 'Blocks as context' }, + { slug: 'agent-platform/local-agents/agent-context/images-as-context', label: 'Images as context' }, + { slug: 'agent-platform/local-agents/agent-context/urls-as-context', label: 'URLs as context' }, + { slug: 'agent-platform/local-agents/agent-context/selection-as-context', label: 'Selection as context' }, + { slug: 'agent-platform/local-agents/agent-context/using-to-add-context', label: 'Using @ to add context' }, + 'agent-platform/capabilities/mcp', + ], + }, + { slug: 'agent-platform/local-agents/interactive-code-review', label: 'Interactive code review' }, + { slug: 'agent-platform/local-agents/active-ai', label: 'Active AI recommendations' }, + 'agent-platform/local-agents/generate', + ], + }, + { + label: 'Third-Party CLI Agents', + items: [ + { slug: 'agent-platform/cli-agents/overview', label: 'Overview' }, + 'agent-platform/cli-agents/claude-code', + 'agent-platform/cli-agents/codex', + 'agent-platform/cli-agents/opencode', + 'agent-platform/cli-agents/rich-input', + 'agent-platform/cli-agents/remote-control', + ], + }, + { + label: 'Oz Cloud Agents & Orchestration', + items: [ + { slug: 'agent-platform/cloud-agents/overview', label: 'Cloud agents overview' }, + { slug: 'agent-platform/cloud-agents/quickstart', label: 'Quickstart' }, + { slug: 'agent-platform/cloud-agents/platform', label: 'Oz platform' }, + { + label: 'Triggers', + items: [ + { slug: 'agent-platform/cloud-agents/triggers', label: 'Overview' }, + { slug: 'agent-platform/cloud-agents/triggers/scheduled-agents-quickstart', label: 'Quickstart' }, + { slug: 'agent-platform/cloud-agents/triggers/scheduled-agents', label: 'Scheduled agents' }, + ], + }, + { + label: 'Integrations', + items: [ + { slug: 'agent-platform/cloud-agents/integrations', label: 'Overview' }, + { slug: 'agent-platform/cloud-agents/integrations/quickstart', label: 'Quickstart' }, + 'agent-platform/cloud-agents/integrations/slack', + 'agent-platform/cloud-agents/integrations/linear', + { + label: 'GitHub Actions', + items: [ + { slug: 'agent-platform/cloud-agents/integrations/github-actions', label: 'Overview' }, + { slug: 'agent-platform/cloud-agents/integrations/quickstart-github-actions', label: 'Quickstart' }, + ], + }, + 'agent-platform/cloud-agents/integrations/azure-devops', + 'agent-platform/cloud-agents/integrations/bitbucket', + 'agent-platform/cloud-agents/integrations/gitlab', + { slug: 'agent-platform/cloud-agents/integrations/cloud-providers', label: 'AWS, GCP, and other cloud providers' }, + { slug: 'agent-platform/cloud-agents/integrations/demo-issue-triage-bot', label: 'Demo: Issue triage bot' }, + ], + }, + 'agent-platform/cloud-agents/environments', + { slug: 'agent-platform/cloud-agents/managing-cloud-agents', label: 'Managing cloud agents' }, + { slug: 'agent-platform/cloud-agents/oz-web-app', label: 'Oz web app' }, + { slug: 'agent-platform/cloud-agents/skills-as-agents', label: 'Skills as agents' }, + { slug: 'agent-platform/cloud-agents/viewing-cloud-agent-runs', label: 'Viewing cloud agent runs' }, + 'agent-platform/cloud-agents/secrets', + { slug: 'agent-platform/cloud-agents/mcp', label: 'MCP servers' }, + { slug: 'agent-platform/cloud-agents/deployment-patterns', label: 'Deployment patterns' }, + { + label: 'Self-hosting', + items: [ + { slug: 'agent-platform/cloud-agents/self-hosting', label: 'Overview' }, + { slug: 'agent-platform/cloud-agents/self-hosting/quickstart', label: 'Quickstart' }, + { slug: 'agent-platform/cloud-agents/self-hosting/managed-docker', label: 'Managed: Docker' }, + { slug: 'agent-platform/cloud-agents/self-hosting/managed-kubernetes', label: 'Managed: Kubernetes' }, + { slug: 'agent-platform/cloud-agents/self-hosting/managed-direct', label: 'Managed: Direct' }, + { slug: 'agent-platform/cloud-agents/self-hosting/unmanaged', label: 'Unmanaged' }, + 'agent-platform/cloud-agents/self-hosting/monitoring', + { slug: 'agent-platform/cloud-agents/self-hosting/reference', label: 'Self-hosted worker reference' }, + 'agent-platform/cloud-agents/self-hosting/security-and-networking', + { slug: 'agent-platform/cloud-agents/self-hosting/troubleshooting', label: 'Troubleshooting' }, + ], + }, + { slug: 'agent-platform/cloud-agents/team-access-billing-and-identity', label: 'Access, billing, and identity' }, + { slug: 'agent-platform/cloud-agents/faqs', label: 'Cloud agent FAQs' }, + ], + }, + ], + }, + { + label: 'Reference', + link: '/reference/', + icon: 'open-book', + items: [ + { slug: 'reference', label: 'Technical reference' }, + { + label: 'CLI', + items: [ + { slug: 'reference/cli', label: 'Oz CLI' }, + { slug: 'reference/cli/quickstart', label: 'Quickstart' }, + { slug: 'reference/cli/api-keys', label: 'API Keys' }, + { slug: 'reference/cli/agent-profiles', label: 'Agent Profiles' }, + { slug: 'reference/cli/mcp-servers', label: 'MCP Servers' }, + { slug: 'reference/cli/skills', label: 'Skills' }, + { slug: 'reference/cli/warp-drive', label: 'Warp Drive Context' }, + { slug: 'reference/cli/integration-setup', label: 'Integration Setup' }, + 'reference/cli/troubleshooting', + ], + }, + { + label: 'API & SDK', + items: [ + { slug: 'reference/api-and-sdk', label: 'Oz API & SDK' }, + { slug: 'reference/api-and-sdk/quickstart', label: 'Quickstart' }, + { label: 'API Reference', link: '/api' }, + 'reference/api-and-sdk/demo-sentry-monitoring-with-sdk', + { + label: 'API Troubleshooting', + items: [ + { slug: 'reference/api-and-sdk/troubleshooting', label: 'API Troubleshooting' }, + { + label: 'Errors', + items: [ + { slug: 'reference/api-and-sdk/troubleshooting/errors', label: 'Errors' }, + 'reference/api-and-sdk/troubleshooting/errors/insufficient-credits', + 'reference/api-and-sdk/troubleshooting/errors/feature-not-available', + 'reference/api-and-sdk/troubleshooting/errors/external-authentication-required', + 'reference/api-and-sdk/troubleshooting/errors/not-authorized', + 'reference/api-and-sdk/troubleshooting/errors/invalid-request', + 'reference/api-and-sdk/troubleshooting/errors/resource-not-found', + 'reference/api-and-sdk/troubleshooting/errors/budget-exceeded', + 'reference/api-and-sdk/troubleshooting/errors/integration-disabled', + 'reference/api-and-sdk/troubleshooting/errors/integration-not-configured', + 'reference/api-and-sdk/troubleshooting/errors/operation-not-supported', + 'reference/api-and-sdk/troubleshooting/errors/environment-setup-failed', + 'reference/api-and-sdk/troubleshooting/errors/content-policy-violation', + 'reference/api-and-sdk/troubleshooting/errors/conflict', + 'reference/api-and-sdk/troubleshooting/errors/authentication-required', + 'reference/api-and-sdk/troubleshooting/errors/resource-unavailable', + 'reference/api-and-sdk/troubleshooting/errors/internal-error', + ], + }, + ], + }, + ], + }, + ], + }, + { + // Link-only topic: navigates straight to the standalone Scalar API + // reference at `/api`. Uses the plugin's `sidebarTopicLinkSchema` + // shape (no `items`) since `/api` isn't a Starlight route and + // doesn't have a per-topic sidebar tree. The `seti:json` icon is a + // graceful fallback for the mobile drawer; the desktop + // `WarpTopicNav` overrides this with a custom `` inline SVG via + // its `CUSTOM_TOPIC_ICONS` map. + label: 'API', + link: '/api', + icon: 'seti:json', + }, + { + label: 'Changelog', + link: '/changelog/', + icon: 'document', + items: [ + { slug: 'changelog', label: 'Changelog' }, + ], + }, + { + label: 'Support & Community', + link: '/support-and-community/', + icon: 'comment', + items: [ + { slug: 'support-and-community', label: 'Support and Community' }, + { + label: 'Community', + items: [ + 'support-and-community/community/contributing', + 'support-and-community/community/warp-preview-and-alpha-program', + { slug: 'support-and-community/community/refer-a-friend', label: 'Refer a Friend & Earn Rewards' }, + 'support-and-community/community/open-source-partnership', + ], + }, + { + label: 'Troubleshooting and support', + items: [ + { slug: 'support-and-community/troubleshooting-and-support/sending-us-feedback', label: 'Sending Feedback & Logs' }, + 'support-and-community/troubleshooting-and-support/known-issues', + 'support-and-community/troubleshooting-and-support/troubleshooting-login-issues', + 'support-and-community/troubleshooting-and-support/using-warp-offline', + 'support-and-community/troubleshooting-and-support/updating-warp', + { slug: 'support-and-community/troubleshooting-and-support/logging-out-and-uninstalling', label: 'Logging Out & Uninstalling' }, + ], + }, + { + label: 'Plans and billing', + items: [ + { slug: 'support-and-community/plans-and-billing', label: 'Overview' }, + { slug: 'support-and-community/plans-and-billing/plans-pricing-refunds', label: 'Plans, Pricing, & Refunds' }, + 'support-and-community/plans-and-billing/credits', + 'support-and-community/plans-and-billing/add-on-credits', + 'support-and-community/plans-and-billing/bring-your-own-api-key', + 'support-and-community/plans-and-billing/overages-legacy', + 'support-and-community/plans-and-billing/pricing-faqs', + ], + }, + { + label: 'Privacy, security, and licensing', + items: [ + 'support-and-community/privacy-and-security/privacy', + 'support-and-community/privacy-and-security/secret-redaction', + 'support-and-community/privacy-and-security/network-log', + { slug: 'support-and-community/community/open-source-licenses', label: 'Open Source Licenses' }, + ], + }, + ], + }, + { + label: 'Enterprise', + link: '/enterprise/', + icon: 'star', + items: [ + { + label: 'Getting started', + items: [ + { slug: 'enterprise', label: 'Overview' }, + { slug: 'enterprise/getting-started/quickstart', label: 'Quick start' }, + { slug: 'enterprise/getting-started/getting-started-enterprise', label: 'Getting started for admins' }, + { slug: 'enterprise/getting-started/getting-started-developers', label: 'Getting started for developers' }, + { slug: 'enterprise/getting-started/faq', label: 'FAQ' }, + ], + }, + { + label: 'Security and compliance', + items: [ + { slug: 'enterprise/security-and-compliance/security-overview', label: 'Security overview' }, + { slug: 'enterprise/security-and-compliance/sso', label: 'Single Sign-On (SSO)' }, + { slug: 'enterprise/security-and-compliance/trust-center', label: 'Trust Center' }, + ], + }, + { + label: 'Team management', + items: [ + 'enterprise/team-management/teams', + { slug: 'enterprise/team-management/admin-panel', label: 'Admin panel' }, + { slug: 'enterprise/team-management/roles-and-permissions', label: 'Roles and permissions' }, + ], + }, + { + label: 'Enterprise features', + items: [ + { slug: 'enterprise/enterprise-features/architecture-and-deployment', label: 'Architecture and deployment' }, + { slug: 'enterprise/enterprise-features/bring-your-own-llm', label: 'Bring your own LLM' }, + ], + }, + { + label: 'Support and resources', + items: [ + 'enterprise/support-and-resources/billing', + { slug: 'enterprise/support-and-resources/troubleshooting-login', label: 'Troubleshooting login' }, + { slug: 'enterprise/support-and-resources/feedback-and-feature-requests', label: 'Feedback and feature requests' }, + ], + }, + ], + }, + { + id: 'guides', + label: 'Guides', + link: '/guides/', + icon: 'puzzle', + items: [ + { slug: 'guides', label: 'Guides' }, + { + label: 'Getting started', + items: [ + 'guides/getting-started/welcome-to-warp', + { slug: 'guides/getting-started/10-coding-features-you-should-know', label: '10 Warp Coding Features You Should Know' }, + { slug: 'guides/getting-started/how-to-customize-warps-appearance', label: 'Customize Warp\'s Appearance' }, + { slug: 'guides/getting-started/how-to-make-warps-ui-more-minimal', label: 'Make Warp\'s UI More Minimal' }, + { slug: 'guides/getting-started/how-to-master-warps-code-review-panel', label: 'Master Warp\'s Code Review Panel' }, + ], + }, + { + label: 'Agent workflows', + items: [ + { slug: 'guides/agent-workflows/how-to-review-ai-generated-code', label: 'Review AI-Generated Code' }, + { slug: 'guides/agent-workflows/how-to-run-multiple-ai-coding-agents', label: 'Run Multiple AI Coding Agents' }, + { slug: 'guides/agent-workflows/how-to-use-voice-and-images-to-prompt-coding-agents', label: 'Use Voice and Images to Prompt Agents' }, + { slug: 'guides/agent-workflows/how-to-explain-your-codebase-using-warp-rust-codebase', label: 'Explain Your Codebase with Agents' }, + { slug: 'guides/agent-workflows/warp-for-product-managers', label: '5 AI Agent Workflows for Product Managers' }, + { slug: 'guides/agent-workflows/how-to-run-3-agents-in-parallel-summarize-logs-analyze-pr-modify-ui', label: 'Run Tasks in Parallel' }, + { slug: 'guides/agent-workflows/how-to-edit-agent-code-in-warp', label: 'Edit Agent-Generated Code in Warp' }, + { slug: 'guides/agent-workflows/how-to-review-prs-like-a-senior-dev', label: 'Review PRs Like a Senior Dev' }, + { slug: 'guides/agent-workflows/using-images-as-context-with-warp', label: 'Use Images as Context for Agents' }, + { slug: 'guides/agent-workflows/understanding-your-codebase', label: 'Understand a Large Codebase with Agents' }, + { slug: 'guides/agent-workflows/running-multiple-agents-at-once-with-warp', label: 'Coordinate Agents on Separate Tasks' }, + ], + }, + { + label: 'Configuration', + items: [ + { slug: 'guides/configuration/how-to-create-project-rules-for-an-existing-project-astro-typescript-tailwind', label: 'Create Project Rules' }, + { slug: 'guides/configuration/how-to-set-coding-best-practices', label: 'Set Coding Best Practices with Rules' }, + { slug: 'guides/configuration/how-to-set-tech-stack-preferences-with-rules', label: 'Set Tech Stack Preferences with Rules' }, + { slug: 'guides/configuration/how-to-set-coding-preferences-with-rules', label: 'Set Coding Preferences with Rules' }, + { slug: 'guides/configuration/how-to-configure-yolo-and-strategic-agent-profiles', label: 'Configure Agent Profiles (YOLO & Strategic)' }, + { slug: 'guides/configuration/how-to-use-agent-profiles-efficiently', label: 'Use Agent Profiles Efficiently' }, + { slug: 'guides/configuration/creating-rules-for-agents', label: 'Create Reusable Rules for Your Team' }, + { slug: 'guides/configuration/trigger-reusable-actions-with-saved-prompts', label: 'Trigger Reusable Actions with Saved Prompts' }, + { slug: 'guides/configuration/how-to-set-up-self-serve-data-analytics-with-skills', label: 'Set Up Self-Serve Data Analytics with Skills' }, + { slug: 'guides/configuration/how-to-sync-your-monorepos', label: 'Sync Your Monorepos' }, + ], + }, + { + label: 'External tools & integrations', + items: [ + { slug: 'guides/external-tools/how-to-set-up-claude-code', label: 'Set Up Claude Code' }, + { slug: 'guides/external-tools/how-to-set-up-codex-cli', label: 'Set Up Codex CLI' }, + { slug: 'guides/external-tools/how-to-set-up-opencode', label: 'Set Up OpenCode' }, + { slug: 'guides/external-tools/how-to-set-up-gemini-cli', label: 'Set Up Gemini CLI' }, + { slug: 'guides/external-tools/how-to-set-up-ollama', label: 'Set Up Ollama for Local Models' }, + { slug: 'guides/external-tools/sentry-mcp-fix-sentry-error-in-empower-website', label: 'Sentry MCP: Fix Errors' }, + { slug: 'guides/external-tools/figma-remote-mcp-create-a-website-from-a-figma-file-from-scratch', label: 'Figma Remote MCP: Create a Website from a Figma File' }, + { slug: 'guides/external-tools/linear-mcp-retrieve-issue-data', label: 'Linear MCP: Retrieve Issue Data' }, + { slug: 'guides/external-tools/linear-mcp-updating-tickets-with-a-lean-build-approach', label: 'Linear MCP: Updating Tickets' }, + { slug: 'guides/external-tools/github-mcp-summarizing-open-prs-and-creating-gh-issues', label: 'GitHub MCP: Summarizing PRs & Creating Issues' }, + { slug: 'guides/external-tools/puppeteer-mcp-scraping-amazon-web-reviews', label: 'Puppeteer MCP: Scraping Web Reviews' }, + { slug: 'guides/external-tools/context7-mcp-update-astro-project-with-best-practices', label: 'Context7 MCP: Update with Best Practices' }, + { slug: 'guides/external-tools/sqlite-and-stripe-mcp-basic-queries-you-can-make-after-set-up', label: 'SQLite and Stripe MCP: Basic Queries' }, + { slug: 'guides/external-tools/using-mcp-servers-with-warp', label: 'Connect Agents to MCP Servers' }, + ], + }, + { + label: 'Build an app in Warp', + items: [ + { slug: 'guides/build-an-app-in-warp/building-a-real-time-chat-app-github-mcp-railway', label: 'Build a Real-time Chat App' }, + { slug: 'guides/build-an-app-in-warp/building-a-chrome-extension-d3js-javascript-html-css', label: 'Build a Chrome Extension' }, + { slug: 'guides/build-an-app-in-warp/building-warps-input-with-warp', label: 'Build Warp\'s Own Input Component' }, + 'guides/build-an-app-in-warp/building-a-slackbot', + ], + }, + { + label: 'DevOps & infrastructure', + items: [ + { slug: 'guides/devops/how-to-analyze-cloud-run-logs-gcloud', label: 'Analyze Cloud Run Logs (gcloud)' }, + { slug: 'guides/devops/how-to-create-a-production-ready-docker-setup', label: 'Create a Production-Ready Docker Setup' }, + { slug: 'guides/devops/improve-your-kubernetes-workflow-kubectl-helm', label: 'Improve Your Kubernetes Workflow' }, + { slug: 'guides/devops/how-to-prevent-secrets-from-leaking', label: 'Prevent Secrets from Leaking' }, + { slug: 'guides/devops/how-to-generate-unit-and-security-tests-to-debug-faster', label: 'Generate Unit and Security Tests' }, + { slug: 'guides/devops/how-to-write-sql-commands-inside-a-postgres-repl', label: 'Write SQL Commands in a Postgres REPL' }, + { slug: 'guides/devops/how-to-create-priority-matrix-for-database-optimization', label: 'Create a Priority Matrix for Database Optimization' }, + ], + }, + { + label: 'Frontend & UI', + items: [ + { slug: 'guides/frontend/how-to-replace-a-ui-element-in-warp-rust-codebase', label: 'Replace a UI Element (Rust Codebase)' }, + { slug: 'guides/frontend/how-to-actually-code-ui-that-matches-your-mockup-react-tailwind', label: 'Code UI That Matches Your Mockup (React + Tailwind)' }, + ], + }, + ], + }, +]; diff --git a/src/styles/custom.css b/src/styles/custom.css new file mode 100644 index 0000000..d0dbb61 --- /dev/null +++ b/src/styles/custom.css @@ -0,0 +1,326 @@ +/* ========================================================================== + Warp Brand Theme for Starlight + Scalar-inspired refinements on top of Warp's warm-dark palette. + ========================================================================== */ + +/* -------------------------------------------------------------------------- + Fonts + Note: the Google Fonts stylesheet is loaded non-blockingly from + src/components/CustomHead.astro (preload + media-swap) instead of via a + blocking @import here. See that file for details. + -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- + Font metric overrides — eliminate layout shift during font swap. + The site loads Google Fonts non-blockingly (media="print" → "all"). + Until Inter arrives, the browser renders with the system font stack. + These @font-face overrides adjust the fallback's metrics to match + Inter's so text doesn't reflow when the swap happens. + -------------------------------------------------------------------------- */ +@font-face { + font-family: 'Inter Fallback'; + src: local('BlinkMacSystemFont'), local('Segoe UI'), local('Roboto'), local('Helvetica Neue'), local('Arial'); + size-adjust: 107%; + ascent-override: 90%; + descent-override: 22%; + line-gap-override: 0%; +} + +@font-face { + font-family: 'JetBrains Mono Fallback'; + src: local('SF Mono'), local('Menlo'), local('Consolas'), local('DejaVu Sans Mono'); + size-adjust: 95%; + ascent-override: 99%; + descent-override: 26%; + line-gap-override: 0%; +} + +/* -------------------------------------------------------------------------- + Dark Mode (default) + + Token values are the Oz webapp brand ladder + (`warp-server/client/packages/agents/src/styles/theme.css`). Mapping: + `--sl-color-black` → Warp legacy dark `#121212` (canvas — a + hair lighter than Oz `gray-950 #0a0d12`, + matching the prior warp.dev product surface) + `--sl-color-gray-1` → Oz `gray-50` (#fafafa, primary text) + `--sl-color-gray-2` → Oz `gray-300` (#dbdbdb, secondary text) + `--sl-color-gray-3` → Oz `gray-400` (#a4a7ae, tertiary) + `--sl-color-gray-4` → Oz `gray-500` (#717680, disabled) + `--sl-color-gray-5` → Oz `gray-700` (#414651, hairlines/inline-code bg) + `--sl-color-gray-6` → Oz `gray-800` (#252b37, hover surfaces) + `--sl-color-white` keeps the warm-white `warp.dev` brand color for + headings, one step above body text for hierarchy. + -------------------------------------------------------------------------- */ +:root { + /* Brand fonts */ + --sl-font: 'Inter', 'Inter Fallback', var(--sl-font-system); + --sl-font-mono: 'JetBrains Mono', 'JetBrains Mono Fallback', var(--sl-font-system-mono); + + /* Accent: Warp blue (inspired by Scalar/terminal palette) */ + --sl-color-accent-low: hsl(210, 40%, 15%); + --sl-color-accent: hsl(207, 80%, 62%); + --sl-color-accent-high: hsl(217, 90%, 84%); + + /* Backgrounds: a single dark canvas — sidebar, header, and content all + share the same fill so the frame reads as one continuous surface, with + hairlines (not fills) doing the separation. */ + --sl-color-black: #121212; /* Warp legacy dark canvas */ + --sl-color-bg: var(--sl-color-black); + --sl-color-bg-nav: var(--sl-color-bg); + --sl-color-bg-sidebar: var(--sl-color-bg); + + /* Gray scale — Oz brand ladder, anchored to `text-primary` near-white + so prose stops reading as the GitBook mid-grey. */ + --sl-color-gray-1: #fafafa; /* Oz gray-50 — primary body text */ + --sl-color-gray-2: #dbdbdb; /* Oz gray-300 — secondary text */ + --sl-color-gray-3: #a4a7ae; /* Oz gray-400 — tertiary text */ + --sl-color-gray-4: #717680; /* Oz gray-500 — disabled */ + --sl-color-gray-5: #414651; /* Oz gray-700 — hairlines / inline-code bg */ + --sl-color-gray-6: #252b37; /* Oz gray-800 — hover surfaces */ + --sl-color-white: hsl(40, 20%, 97%); /* warm off-white #faf9f6 — headings */ + + /* Text — body lands on `gray-1` (Oz `text-primary`) for high contrast. + Headings continue to use `--sl-color-white` for one extra step. */ + --sl-color-text: var(--sl-color-gray-1); + --sl-color-text-accent: var(--sl-color-accent-high); + + /* Inline code */ + --sl-color-bg-inline-code: var(--sl-color-gray-5); + + /* Hairlines — Scalar-inspired: thinner, lower opacity */ + --sl-color-hairline-light: rgba(255, 255, 255, 0.08); + --sl-color-hairline: rgba(255, 255, 255, 0.06); + --sl-color-hairline-shade: rgba(255, 255, 255, 0.04); + + /* Typography scale — clear heading hierarchy */ + --sl-text-h1: 2rem; /* 32px */ + --sl-text-h2: 1.5rem; /* 24px */ + --sl-text-h3: 1.25rem; /* 20px */ + --sl-text-h4: 1.125rem; /* 18px */ + --sl-text-body: 1rem; + --sl-text-sm: 0.875rem; + --sl-text-xs: 0.8125rem; + --sl-text-2xs: 0.75rem; + --sl-line-height-headings: 1.2; + --sl-line-height: 1.6; /* tighter than Starlight's 1.75 default */ + + /* Radius scale — four tokens cover every chrome surface on the site. + Defined here (not duplicated per theme) since radii don't change + between dark and light. Consumers should prefer these over literals + so the scale can be shifted in one place. */ + --sl-radius-xs: 2px; /* small chips, focus rings */ + --sl-radius-sm: 4px; /* buttons, leaf links, search pill */ + --sl-radius-md: 6px; /* cards, asides, code blocks, file tree */ + --sl-radius-lg: 8px; /* dropdown panel, video embeds, Kapa dialog */ +} + +/* -------------------------------------------------------------------------- + Light Mode + + Mirrors the Oz webapp ladder in light theme: + `--sl-color-black` (canvas) → Oz `--color-bg-primary` (#ffffff) + `--sl-color-white` → Oz `gray-950` (#0a0d12, headings) + `--sl-color-gray-1` → Oz `gray-900` (#181d27, primary body text) + `--sl-color-gray-2` → Oz `gray-700` (#414651, secondary text) + `--sl-color-gray-3` → Oz `gray-600` (#535862, tertiary) + `--sl-color-gray-4` → Oz `gray-500` (#717680, disabled) + `--sl-color-gray-5` → Oz `gray-300` (#dbdbdb, subtle borders) + `--sl-color-gray-6` → Oz `gray-100` (#f3f3f3, inline-code bg) + `--sl-color-gray-7` → Oz `gray-50` (#fafafa, soft hover fills) + -------------------------------------------------------------------------- */ +:root[data-theme='light'], +[data-theme='light'] ::backdrop { + /* Accent: darker blue for readability on light backgrounds */ + --sl-color-accent-low: hsl(210, 40%, 92%); + --sl-color-accent: hsl(207, 80%, 40%); + --sl-color-accent-high: hsl(210, 60%, 28%); + + /* Single pure-white canvas to match the Oz webapp. The previous + `#faf9f6` warm tint (warp.dev marketing site bg) read dim against the + Oz product surface — pull docs alongside the product chrome. */ + --sl-color-black: #ffffff; /* Oz bg-primary */ + --sl-color-bg: var(--sl-color-black); + --sl-color-bg-nav: var(--sl-color-bg); + --sl-color-bg-sidebar: var(--sl-color-bg); + + /* Gray scale — Oz brand ladder, anchored to `text-primary` near-black + so prose contrasts cleanly against pure-white. */ + --sl-color-white: #0a0d12; /* Oz gray-950 — headings */ + --sl-color-gray-1: #181d27; /* Oz gray-900 — primary body text */ + --sl-color-gray-2: #414651; /* Oz gray-700 — secondary text */ + --sl-color-gray-3: #535862; /* Oz gray-600 — tertiary */ + --sl-color-gray-4: #717680; /* Oz gray-500 — disabled */ + --sl-color-gray-5: #dbdbdb; /* Oz gray-300 — subtle borders */ + --sl-color-gray-6: #f3f3f3; /* Oz gray-100 — inline-code bg / soft fills */ + --sl-color-gray-7: #fafafa; /* Oz gray-50 — hover surfaces */ + + /* Text */ + --sl-color-text-accent: var(--sl-color-accent); + + /* Inline code */ + --sl-color-bg-inline-code: var(--sl-color-gray-6); + + /* Hairlines — Scalar-inspired: ultra-subtle */ + --sl-color-hairline-light: rgba(0, 0, 0, 0.08); + --sl-color-hairline: rgba(0, 0, 0, 0.06); + --sl-color-hairline-shade: rgba(0, 0, 0, 0.04); +} + +/* -------------------------------------------------------------------------- + Code block token colors (from Warp's dark terminal ANSI palette) + -------------------------------------------------------------------------- */ +:root { + --astro-code-token-string: #b4fa72; /* Warp green */ + --astro-code-token-string-expression: #b4fa72; + --astro-code-token-keyword: #d0d1fe; /* Warp cyan/purple */ + --astro-code-token-constant: #a5d5fe; /* Warp blue */ + --astro-code-token-function: #ff8ffd; /* Warp magenta */ + --astro-code-token-parameter: #fefdc2; /* Warp yellow */ + --astro-code-token-comment: hsl(210, 4%, 45%); + --astro-code-token-punctuation: hsl(210, 4%, 65%); + --astro-code-token-link: #a5d5fe; +} + +:root[data-theme='light'] { + --astro-code-token-string: #10a778; + --astro-code-token-string-expression: #10a778; + --astro-code-token-keyword: #523c79; + --astro-code-token-constant: #008ec4; + --astro-code-token-function: #c30771; + --astro-code-token-parameter: #a89c14; + --astro-code-token-comment: hsl(210, 3%, 50%); + --astro-code-token-punctuation: hsl(210, 3%, 40%); + --astro-code-token-link: #008ec4; +} + +/* -------------------------------------------------------------------------- + Global polish + -------------------------------------------------------------------------- */ + +/* Smoother font rendering */ +body { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* Editorial heading treatment — slight negative tracking like Scalar/Warp */ +.sl-markdown-content h1, +.sl-markdown-content h2, +.sl-markdown-content h3, +.sl-markdown-content h4 { + letter-spacing: -0.02em; +} + +/* H1 gets heavier weight to separate it from H2-H4 */ +.sl-markdown-content h1 { + font-weight: 700; +} + +/* Align sidebar topics flush with the sidebar's left edge */ +.starlight-sidebar-topics a { + padding-inline-start: 0; +} + +/* Shrink the right "On this page" TOC panel */ +:root { + --sl-toc-width: 16rem; +} + +@media (min-width: 72rem) { + .right-sidebar-container { + width: var(--sl-toc-width); + } + + [data-has-sidebar][data-has-toc] .main-pane { + width: calc(100% - var(--sl-toc-width)); + } + + /* + * .right-sidebar is position:fixed with width:100vw, so its visible area + * is only --sl-toc-width wide. Constrain the content box to that width so + * text wraps instead of overflowing off-screen. + */ + .right-sidebar-panel .sl-container { + width: calc(var(--sl-toc-width) - 2 * var(--sl-sidebar-pad-x)); + max-width: 100%; + } +} + +/* Belt-and-braces text color for active items inside the sidebar in light + mode. The primary rule lives in warp-components.css §1 (which sets + `color: var(--sl-color-white)` = `#0a0d12` against a tinted bg) and + wins on specificity. We keep this fallback ONLY for the sidebar so a + future refactor of the §1 rule still leaves a sane color in place. + + Critical: the selector MUST stay scoped to `.sidebar-content`. Earlier + it was a bare `[aria-current='page']` which leaked into the topic nav + in WarpTopicNav.astro and painted the active topic warm-white on the + warm-white page bg — invisible. */ +:root[data-theme='light'] .sidebar-content [aria-current='page'], +:root[data-theme='light'] .sidebar-content [aria-current='page']:hover, +:root[data-theme='light'] .sidebar-content [aria-current='page']:focus { + color: #faf9f6; +} + +/* Center all images in content by default (excluding those inside tables) */ +.sl-markdown-content :not(table) > img, +.sl-markdown-content p > img { + display: block; + margin-left: auto; + margin-right: auto; +} + +/* Center and constrain main content — Scalar uses a tighter column */ +.main-pane .sl-container { + max-width: 46rem; + margin-left: auto; + margin-right: auto; +} + +/* Tighter paragraph spacing for denser, more editorial feel */ +.sl-markdown-content p { + margin-block: 1em; +} + +/* Heading spacing — more breathing room between sections (Scalar-inspired) */ +.sl-markdown-content h2 { + margin-top: 2.5em; + margin-bottom: 0.75em; +} +.sl-markdown-content h3 { + margin-top: 2em; + margin-bottom: 0.5em; +} +.sl-markdown-content h4 { + margin-top: 1.5em; + margin-bottom: 0.5em; +} + +/* List spacing — tighter indent (24px vs browser default 40px) and more + breathing room between items (8px vs Starlight's 4px). + + Both rules use `:not(:where(.not-content *))` to mirror Starlight's own + prose-list scoping (`@astrojs/starlight/style/markdown.css`). Without + the exclusion: + * The `padding-inline-start` rule overrides Starlight's + `[role=tablist] { padding: 0 }` and pushes the first tab in by + 24px, since the tablist `