diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000000..e1ded3492d0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,30 @@ +name: CI + +on: + push: + branches: [main, dev] + pull_request: + branches: [main, dev] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: oven-sh/setup-bun@v1 + with: + bun-version: latest + + - name: Setup environment + run: | + mkdir -p ~/.local/share/opencode/log + git config --global user.name "CI" + git config --global user.email "ci@test.local" + + - run: bun install + + - run: bun typecheck + + - working-directory: packages/opencode + run: bun test diff --git a/.github/workflows/daily-issues-recap.yml b/.github/workflows/daily-issues-recap.yml deleted file mode 100644 index a333e5365f9..00000000000 --- a/.github/workflows/daily-issues-recap.yml +++ /dev/null @@ -1,166 +0,0 @@ -name: Daily Issues Recap - -on: - schedule: - # Run at 6 PM EST (23:00 UTC, or 22:00 UTC during daylight saving) - - cron: "0 23 * * *" - workflow_dispatch: # Allow manual trigger for testing - -jobs: - daily-recap: - runs-on: blacksmith-4vcpu-ubuntu-2404 - permissions: - contents: read - issues: read - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - uses: ./.github/actions/setup-bun - - - name: Install opencode - run: curl -fsSL https://opencode.ai/install | bash - - - name: Generate daily issues recap - id: recap - env: - OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - OPENCODE_PERMISSION: | - { - "bash": { - "*": "deny", - "gh issue*": "allow", - "gh search*": "allow" - }, - "webfetch": "deny", - "edit": "deny", - "write": "deny" - } - run: | - # Get today's date range - TODAY=$(date -u +%Y-%m-%d) - - opencode run -m opencode/claude-sonnet-4-5 "Generate a daily issues recap for the OpenCode repository. - - TODAY'S DATE: ${TODAY} - - STEP 1: Gather today's issues - Search for all issues created today (${TODAY}) using: - gh issue list --repo ${{ github.repository }} --state all --search \"created:${TODAY}\" --json number,title,body,labels,state,comments,createdAt,author --limit 500 - - STEP 2: Analyze and categorize - For each issue created today, categorize it: - - **Severity Assessment:** - - CRITICAL: Crashes, data loss, security issues, blocks major functionality - - HIGH: Significant bugs affecting many users, important features broken - - MEDIUM: Bugs with workarounds, minor features broken - - LOW: Minor issues, cosmetic, nice-to-haves - - **Activity Assessment:** - - Note issues with high comment counts or engagement - - Note issues from repeat reporters (check if author has filed before) - - STEP 3: Cross-reference with existing issues - For issues that seem like feature requests or recurring bugs: - - Search for similar older issues to identify patterns - - Note if this is a frequently requested feature - - Identify any issues that are duplicates of long-standing requests - - STEP 4: Generate the recap - Create a structured recap with these sections: - - ===DISCORD_START=== - **Daily Issues Recap - ${TODAY}** - - **Summary Stats** - - Total issues opened today: [count] - - By category: [bugs/features/questions] - - **Critical/High Priority Issues** - [List any CRITICAL or HIGH severity issues with brief descriptions and issue numbers] - - **Most Active/Discussed** - [Issues with significant engagement or from active community members] - - **Trending Topics** - [Patterns noticed - e.g., 'Multiple reports about X', 'Continued interest in Y feature'] - - **Duplicates & Related** - [Issues that relate to existing open issues] - ===DISCORD_END=== - - STEP 5: Format for Discord - Format the recap as a Discord-compatible message: - - Use Discord markdown (**, __, etc.) - - BE EXTREMELY CONCISE - this is an EOD summary, not a detailed report - - Use hyperlinked issue numbers with suppressed embeds: [#1234]() - - Group related issues on single lines where possible - - Add emoji sparingly for critical items only - - HARD LIMIT: Keep under 1800 characters total - - Skip sections that have nothing notable (e.g., if no critical issues, omit that section) - - Prioritize signal over completeness - only surface what matters - - OUTPUT: Output ONLY the content between ===DISCORD_START=== and ===DISCORD_END=== markers. Include the markers so I can extract it." > /tmp/recap_raw.txt - - # Extract only the Discord message between markers - sed -n '/===DISCORD_START===/,/===DISCORD_END===/p' /tmp/recap_raw.txt | grep -v '===DISCORD' > /tmp/recap.txt - - echo "recap_file=/tmp/recap.txt" >> $GITHUB_OUTPUT - - - name: Post to Discord - env: - DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_ISSUES_WEBHOOK_URL }} - run: | - if [ -z "$DISCORD_WEBHOOK_URL" ]; then - echo "Warning: DISCORD_ISSUES_WEBHOOK_URL secret not set, skipping Discord post" - cat /tmp/recap.txt - exit 0 - fi - - # Read the recap - RECAP_RAW=$(cat /tmp/recap.txt) - RECAP_LENGTH=${#RECAP_RAW} - - echo "Recap length: ${RECAP_LENGTH} chars" - - # Function to post a message to Discord - post_to_discord() { - local msg="$1" - local content=$(echo "$msg" | jq -Rs '.') - curl -s -H "Content-Type: application/json" \ - -X POST \ - -d "{\"content\": ${content}}" \ - "$DISCORD_WEBHOOK_URL" - sleep 1 - } - - # If under limit, send as single message - if [ "$RECAP_LENGTH" -le 1950 ]; then - post_to_discord "$RECAP_RAW" - else - echo "Splitting into multiple messages..." - remaining="$RECAP_RAW" - while [ ${#remaining} -gt 0 ]; do - if [ ${#remaining} -le 1950 ]; then - post_to_discord "$remaining" - break - else - chunk="${remaining:0:1900}" - last_newline=$(echo "$chunk" | grep -bo $'\n' | tail -1 | cut -d: -f1) - if [ -n "$last_newline" ] && [ "$last_newline" -gt 500 ]; then - chunk="${remaining:0:$last_newline}" - remaining="${remaining:$((last_newline+1))}" - else - chunk="${remaining:0:1900}" - remaining="${remaining:1900}" - fi - post_to_discord "$chunk" - fi - done - fi - - echo "Posted daily recap to Discord" diff --git a/.github/workflows/daily-pr-recap.yml b/.github/workflows/daily-pr-recap.yml deleted file mode 100644 index 7c8bab395f6..00000000000 --- a/.github/workflows/daily-pr-recap.yml +++ /dev/null @@ -1,169 +0,0 @@ -name: Daily PR Recap - -on: - schedule: - # Run at 5pm EST (22:00 UTC, or 21:00 UTC during daylight saving) - - cron: "0 22 * * *" - workflow_dispatch: # Allow manual trigger for testing - -jobs: - pr-recap: - runs-on: blacksmith-4vcpu-ubuntu-2404 - permissions: - contents: read - pull-requests: read - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - uses: ./.github/actions/setup-bun - - - name: Install opencode - run: curl -fsSL https://opencode.ai/install | bash - - - name: Generate daily PR recap - id: recap - env: - OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - OPENCODE_PERMISSION: | - { - "bash": { - "*": "deny", - "gh pr*": "allow", - "gh search*": "allow" - }, - "webfetch": "deny", - "edit": "deny", - "write": "deny" - } - run: | - TODAY=$(date -u +%Y-%m-%d) - - opencode run -m opencode/claude-sonnet-4-5 "Generate a daily PR activity recap for the OpenCode repository. - - TODAY'S DATE: ${TODAY} - - STEP 1: Gather PR data - Run these commands to gather PR information. ONLY include PRs created or updated TODAY (${TODAY}): - - # PRs created today - gh pr list --repo ${{ github.repository }} --state all --search \"created:${TODAY}\" --json number,title,author,labels,createdAt,updatedAt,reviewDecision,isDraft,additions,deletions --limit 100 - - # PRs with activity today (updated today) - gh pr list --repo ${{ github.repository }} --state open --search \"updated:${TODAY}\" --json number,title,author,labels,createdAt,updatedAt,reviewDecision,isDraft,additions,deletions --limit 100 - - - - STEP 2: For high-activity PRs, check comment counts - For promising PRs, run: - gh pr view [NUMBER] --repo ${{ github.repository }} --json comments --jq '[.comments[] | select(.author.login != \"copilot-pull-request-reviewer\" and .author.login != \"github-actions\")] | length' - - IMPORTANT: When counting comments/activity, EXCLUDE these bot accounts: - - copilot-pull-request-reviewer - - github-actions - - STEP 3: Identify what matters (ONLY from today's PRs) - - **Bug Fixes From Today:** - - PRs with 'fix' or 'bug' in title created/updated today - - Small bug fixes (< 100 lines changed) that are easy to review - - Bug fixes from community contributors - - **High Activity Today:** - - PRs with significant human comments today (excluding bots listed above) - - PRs with back-and-forth discussion today - - **Quick Wins:** - - Small PRs (< 50 lines) that are approved or nearly approved - - PRs that just need a final review - - STEP 4: Generate the recap - Create a structured recap: - - ===DISCORD_START=== - **Daily PR Recap - ${TODAY}** - - **New PRs Today** - [PRs opened today - group by type: bug fixes, features, etc.] - - **Active PRs Today** - [PRs with activity/updates today - significant discussion] - - **Quick Wins** - [Small PRs ready to merge] - ===DISCORD_END=== - - STEP 5: Format for Discord - - Use Discord markdown (**, __, etc.) - - BE EXTREMELY CONCISE - surface what we might miss - - Use hyperlinked PR numbers with suppressed embeds: [#1234]() - - Include PR author: [#1234]() (@author) - - For bug fixes, add brief description of what it fixes - - Show line count for quick wins: \"(+15/-3 lines)\" - - HARD LIMIT: Keep under 1800 characters total - - Skip empty sections - - Focus on PRs that need human eyes - - OUTPUT: Output ONLY the content between ===DISCORD_START=== and ===DISCORD_END=== markers. Include the markers so I can extract it." > /tmp/pr_recap_raw.txt - - # Extract only the Discord message between markers - sed -n '/===DISCORD_START===/,/===DISCORD_END===/p' /tmp/pr_recap_raw.txt | grep -v '===DISCORD' > /tmp/pr_recap.txt - - echo "recap_file=/tmp/pr_recap.txt" >> $GITHUB_OUTPUT - - - name: Post to Discord - env: - DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_ISSUES_WEBHOOK_URL }} - run: | - if [ -z "$DISCORD_WEBHOOK_URL" ]; then - echo "Warning: DISCORD_ISSUES_WEBHOOK_URL secret not set, skipping Discord post" - cat /tmp/pr_recap.txt - exit 0 - fi - - # Read the recap - RECAP_RAW=$(cat /tmp/pr_recap.txt) - RECAP_LENGTH=${#RECAP_RAW} - - echo "Recap length: ${RECAP_LENGTH} chars" - - # Function to post a message to Discord - post_to_discord() { - local msg="$1" - local content=$(echo "$msg" | jq -Rs '.') - curl -s -H "Content-Type: application/json" \ - -X POST \ - -d "{\"content\": ${content}}" \ - "$DISCORD_WEBHOOK_URL" - sleep 1 - } - - # If under limit, send as single message - if [ "$RECAP_LENGTH" -le 1950 ]; then - post_to_discord "$RECAP_RAW" - else - echo "Splitting into multiple messages..." - remaining="$RECAP_RAW" - while [ ${#remaining} -gt 0 ]; do - if [ ${#remaining} -le 1950 ]; then - post_to_discord "$remaining" - break - else - chunk="${remaining:0:1900}" - last_newline=$(echo "$chunk" | grep -bo $'\n' | tail -1 | cut -d: -f1) - if [ -n "$last_newline" ] && [ "$last_newline" -gt 500 ]; then - chunk="${remaining:0:$last_newline}" - remaining="${remaining:$((last_newline+1))}" - else - chunk="${remaining:0:1900}" - remaining="${remaining:1900}" - fi - post_to_discord "$chunk" - fi - done - fi - - echo "Posted daily PR recap to Discord" diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 25466a63e06..00000000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: deploy - -on: - push: - branches: - - dev - - production - workflow_dispatch: - -concurrency: ${{ github.workflow }}-${{ github.ref }} - -jobs: - deploy: - runs-on: blacksmith-4vcpu-ubuntu-2404 - steps: - - uses: actions/checkout@v3 - - - uses: ./.github/actions/setup-bun - - - uses: actions/setup-node@v4 - with: - node-version: "24" - - - run: bun sst deploy --stage=${{ github.ref_name }} - env: - CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} - PLANETSCALE_SERVICE_TOKEN_NAME: ${{ secrets.PLANETSCALE_SERVICE_TOKEN_NAME }} - PLANETSCALE_SERVICE_TOKEN: ${{ secrets.PLANETSCALE_SERVICE_TOKEN }} - STRIPE_SECRET_KEY: ${{ github.ref_name == 'production' && secrets.STRIPE_SECRET_KEY_PROD || secrets.STRIPE_SECRET_KEY_DEV }} diff --git a/.github/workflows/docs-update.yml b/.github/workflows/docs-update.yml deleted file mode 100644 index a8dd2ae4f2b..00000000000 --- a/.github/workflows/docs-update.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: Docs Update - -on: - schedule: - - cron: "0 */12 * * *" - workflow_dispatch: - -env: - LOOKBACK_HOURS: 4 - -jobs: - update-docs: - if: github.repository == 'sst/opencode' - runs-on: blacksmith-4vcpu-ubuntu-2404 - permissions: - id-token: write - contents: write - pull-requests: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Fetch full history to access commits - - - name: Setup Bun - uses: ./.github/actions/setup-bun - - - name: Get recent commits - id: commits - run: | - COMMITS=$(git log --since="${{ env.LOOKBACK_HOURS }} hours ago" --pretty=format:"- %h %s" 2>/dev/null || echo "") - if [ -z "$COMMITS" ]; then - echo "No commits in the last ${{ env.LOOKBACK_HOURS }} hours" - echo "has_commits=false" >> $GITHUB_OUTPUT - else - echo "has_commits=true" >> $GITHUB_OUTPUT - { - echo "list<> $GITHUB_OUTPUT - fi - - - name: Run opencode - if: steps.commits.outputs.has_commits == 'true' - uses: sst/opencode/github@latest - env: - OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - with: - model: opencode/gpt-5.2 - agent: docs - prompt: | - Review the following commits from the last ${{ env.LOOKBACK_HOURS }} hours and identify any new features that may need documentation. - - - ${{ steps.commits.outputs.list }} - - - Steps: - 1. For each commit that looks like a new feature or significant change: - - Read the changed files to understand what was added - - Check if the feature is already documented in packages/web/src/content/docs/* - 2. If you find undocumented features: - - Update the relevant documentation files in packages/web/src/content/docs/* - - Follow the existing documentation style and structure - - Make sure to document the feature clearly with examples where appropriate - 3. If all new features are already documented, report that no updates are needed - 4. If you are creating a new documentation file be sure to update packages/web/astro.config.mjs too. - - Focus on user-facing features and API changes. Skip internal refactors, bug fixes, and test updates unless they affect user-facing behavior. - Don't feel the need to document every little thing. It is perfectly okay to make 0 changes at all. - Try to keep documentation only for large features or changes that already have a good spot to be documented. diff --git a/.github/workflows/duplicate-issues.yml b/.github/workflows/duplicate-issues.yml deleted file mode 100644 index 53aa2a725eb..00000000000 --- a/.github/workflows/duplicate-issues.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Duplicate Issue Detection - -on: - issues: - types: [opened] - -jobs: - check-duplicates: - runs-on: blacksmith-4vcpu-ubuntu-2404 - permissions: - contents: read - issues: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - uses: ./.github/actions/setup-bun - - - name: Install opencode - run: curl -fsSL https://opencode.ai/install | bash - - - name: Check for duplicate issues - env: - OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - OPENCODE_PERMISSION: | - { - "bash": { - "*": "deny", - "gh issue*": "allow" - }, - "webfetch": "deny" - } - run: | - opencode run -m opencode/claude-haiku-4-5 "A new issue has been created:' - - Issue number: - ${{ github.event.issue.number }} - - Lookup this issue and search through existing issues (excluding #${{ github.event.issue.number }}) in this repository to find any potential duplicates of this new issue. - Consider: - 1. Similar titles or descriptions - 2. Same error messages or symptoms - 3. Related functionality or components - 4. Similar feature requests - - If you find any potential duplicates, please comment on the new issue with: - - A brief explanation of why it might be a duplicate - - Links to the potentially duplicate issues - - A suggestion to check those issues first - - Use this format for the comment: - 'This issue might be a duplicate of existing issues. Please check: - - #[issue_number]: [brief description of similarity] - - Feel free to ignore if none of these address your specific case.' - - Additionally, if the issue mentions keybinds, keyboard shortcuts, or key bindings, please add a comment mentioning the pinned keybinds issue #4997: - 'For keybind-related issues, please also check our pinned keybinds documentation: #4997' - - If no clear duplicates are found, do not comment." diff --git a/.github/workflows/duplicate-prs.yml b/.github/workflows/duplicate-prs.yml deleted file mode 100644 index 32606858958..00000000000 --- a/.github/workflows/duplicate-prs.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: Duplicate PR Check - -on: - pull_request_target: - types: [opened] - -jobs: - check-duplicates: - if: | - github.event.pull_request.user.login != 'actions-user' && - github.event.pull_request.user.login != 'opencode' && - github.event.pull_request.user.login != 'rekram1-node' && - github.event.pull_request.user.login != 'thdxr' && - github.event.pull_request.user.login != 'kommander' && - github.event.pull_request.user.login != 'jayair' && - github.event.pull_request.user.login != 'fwang' && - github.event.pull_request.user.login != 'adamdotdevin' && - github.event.pull_request.user.login != 'iamdavidhill' && - github.event.pull_request.user.login != 'opencode-agent[bot]' - runs-on: blacksmith-4vcpu-ubuntu-2404 - permissions: - contents: read - pull-requests: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - name: Setup Bun - uses: ./.github/actions/setup-bun - - - name: Install dependencies - run: bun install - - - name: Install opencode - run: curl -fsSL https://opencode.ai/install | bash - - - name: Build prompt - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ github.event.pull_request.number }} - run: | - { - echo "Check for duplicate PRs related to this new PR:" - echo "" - echo "CURRENT_PR_NUMBER: $PR_NUMBER" - echo "" - echo "Title: $(gh pr view "$PR_NUMBER" --json title --jq .title)" - echo "" - echo "Description:" - gh pr view "$PR_NUMBER" --json body --jq .body - } > pr_info.txt - - - name: Check for duplicate PRs - env: - OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ github.event.pull_request.number }} - run: | - COMMENT=$(bun script/duplicate-pr.ts -f pr_info.txt "Check the attached file for PR details and search for duplicates") - - gh pr comment "$PR_NUMBER" --body "_The following comment was made by an LLM, it may be inaccurate:_ - - $COMMENT" diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml deleted file mode 100644 index 29cc9895393..00000000000 --- a/.github/workflows/generate.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: generate - -on: - push: - branches: - - dev - workflow_dispatch: - -jobs: - generate: - runs-on: blacksmith-4vcpu-ubuntu-2404 - permissions: - contents: write - pull-requests: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} - ref: ${{ github.event.pull_request.head.ref || github.ref_name }} - - - name: Setup Bun - uses: ./.github/actions/setup-bun - - - name: Generate - run: ./script/generate.ts - - - name: Commit and push - run: | - if [ -z "$(git status --porcelain)" ]; then - echo "No changes to commit" - exit 0 - fi - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - git add -A - git commit -m "chore: generate" - git push origin HEAD:${{ github.ref_name }} --no-verify - # if ! git push origin HEAD:${{ github.event.pull_request.head.ref || github.ref_name }} --no-verify; then - # echo "" - # echo "============================================" - # echo "Failed to push generated code." - # echo "Please run locally and push:" - # echo "" - # echo " ./script/generate.ts" - # echo " git add -A && git commit -m \"chore: generate\" && git push" - # echo "" - # echo "============================================" - # exit 1 - # fi diff --git a/.github/workflows/nix-desktop.yml b/.github/workflows/nix-desktop.yml deleted file mode 100644 index 3d7c4803133..00000000000 --- a/.github/workflows/nix-desktop.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: nix desktop - -on: - push: - branches: [dev] - paths: - - "flake.nix" - - "flake.lock" - - "nix/**" - - "packages/app/**" - - "packages/desktop/**" - - ".github/workflows/nix-desktop.yml" - pull_request: - paths: - - "flake.nix" - - "flake.lock" - - "nix/**" - - "packages/app/**" - - "packages/desktop/**" - - ".github/workflows/nix-desktop.yml" - workflow_dispatch: - -jobs: - build-desktop: - strategy: - fail-fast: false - matrix: - os: - - blacksmith-4vcpu-ubuntu-2404 - - blacksmith-4vcpu-ubuntu-2404-arm - - macos-15-intel - - macos-latest - runs-on: ${{ matrix.os }} - timeout-minutes: 60 - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Setup Nix - uses: nixbuild/nix-quick-install-action@v34 - - - name: Build desktop via flake - run: | - set -euo pipefail - nix --version - nix build .#desktop -L diff --git a/.github/workflows/notify-discord.yml b/.github/workflows/notify-discord.yml deleted file mode 100644 index 62577ecf00e..00000000000 --- a/.github/workflows/notify-discord.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: discord - -on: - release: - types: [released] # fires when a draft release is published - -jobs: - notify: - runs-on: blacksmith-4vcpu-ubuntu-2404 - steps: - - name: Send nicely-formatted embed to Discord - uses: SethCohen/github-releases-to-discord@v1 - with: - webhook_url: ${{ secrets.DISCORD_WEBHOOK }} diff --git a/.github/workflows/opencode.yml b/.github/workflows/opencode.yml deleted file mode 100644 index 76e75fcaefb..00000000000 --- a/.github/workflows/opencode.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: opencode - -on: - issue_comment: - types: [created] - pull_request_review_comment: - types: [created] - -jobs: - opencode: - if: | - contains(github.event.comment.body, ' /oc') || - startsWith(github.event.comment.body, '/oc') || - contains(github.event.comment.body, ' /opencode') || - startsWith(github.event.comment.body, '/opencode') - runs-on: blacksmith-4vcpu-ubuntu-2404 - permissions: - id-token: write - contents: read - pull-requests: read - issues: read - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - uses: ./.github/actions/setup-bun - - - name: Run opencode - uses: anomalyco/opencode/github@latest - env: - OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - OPENCODE_PERMISSION: '{"bash": "deny"}' - with: - model: opencode/claude-opus-4-5 diff --git a/.github/workflows/pr-standards.yml b/.github/workflows/pr-standards.yml deleted file mode 100644 index c1cf1756787..00000000000 --- a/.github/workflows/pr-standards.yml +++ /dev/null @@ -1,139 +0,0 @@ -name: PR Standards - -on: - pull_request_target: - types: [opened, edited, synchronize] - -jobs: - check-standards: - if: | - github.event.pull_request.user.login != 'actions-user' && - github.event.pull_request.user.login != 'opencode' && - github.event.pull_request.user.login != 'rekram1-node' && - github.event.pull_request.user.login != 'thdxr' && - github.event.pull_request.user.login != 'kommander' && - github.event.pull_request.user.login != 'jayair' && - github.event.pull_request.user.login != 'fwang' && - github.event.pull_request.user.login != 'adamdotdevin' && - github.event.pull_request.user.login != 'iamdavidhill' && - github.event.pull_request.user.login != 'opencode-agent[bot]' - runs-on: ubuntu-latest - permissions: - pull-requests: write - steps: - - name: Check PR standards - uses: actions/github-script@v7 - with: - script: | - const pr = context.payload.pull_request; - const title = pr.title; - - async function addLabel(label) { - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: pr.number, - labels: [label] - }); - } - - async function removeLabel(label) { - try { - await github.rest.issues.removeLabel({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: pr.number, - name: label - }); - } catch (e) { - // Label wasn't present, ignore - } - } - - async function comment(marker, body) { - const markerText = ``; - const { data: comments } = await github.rest.issues.listComments({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: pr.number - }); - - const existing = comments.find(c => c.body.includes(markerText)); - if (existing) return; - - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: pr.number, - body: markerText + '\n' + body - }); - } - - // Step 1: Check title format - // Matches: feat:, feat(scope):, feat (scope):, etc. - const titlePattern = /^(feat|fix|docs|chore|refactor|test)\s*(\([a-zA-Z0-9-]+\))?\s*:/; - const hasValidTitle = titlePattern.test(title); - - if (!hasValidTitle) { - await addLabel('needs:title'); - await comment('title', `Hey! Your PR title \`${title}\` doesn't follow conventional commit format. - - Please update it to start with one of: - - \`feat:\` or \`feat(scope):\` new feature - - \`fix:\` or \`fix(scope):\` bug fix - - \`docs:\` or \`docs(scope):\` documentation changes - - \`chore:\` or \`chore(scope):\` maintenance tasks - - \`refactor:\` or \`refactor(scope):\` code refactoring - - \`test:\` or \`test(scope):\` adding or updating tests - - Where \`scope\` is the package name (e.g., \`app\`, \`desktop\`, \`opencode\`). - - See [CONTRIBUTING.md](../blob/dev/CONTRIBUTING.md#pr-titles) for details.`); - return; - } - - await removeLabel('needs:title'); - - // Step 2: Check for linked issue (skip for docs/refactor PRs) - const skipIssueCheck = /^(docs|refactor)\s*(\([a-zA-Z0-9-]+\))?\s*:/.test(title); - if (skipIssueCheck) { - await removeLabel('needs:issue'); - console.log('Skipping issue check for docs/refactor PR'); - return; - } - const query = ` - query($owner: String!, $repo: String!, $number: Int!) { - repository(owner: $owner, name: $repo) { - pullRequest(number: $number) { - closingIssuesReferences(first: 1) { - totalCount - } - } - } - } - `; - - const result = await github.graphql(query, { - owner: context.repo.owner, - repo: context.repo.repo, - number: pr.number - }); - - const linkedIssues = result.repository.pullRequest.closingIssuesReferences.totalCount; - - if (linkedIssues === 0) { - await addLabel('needs:issue'); - await comment('issue', `Thanks for your contribution! - - This PR doesn't have a linked issue. All PRs must reference an existing issue. - - Please: - 1. Open an issue describing the bug/feature (if one doesn't exist) - 2. Add \`Fixes #\` or \`Closes #\` to this PR description - - See [CONTRIBUTING.md](../blob/dev/CONTRIBUTING.md#issue-first-policy) for details.`); - return; - } - - await removeLabel('needs:issue'); - console.log('PR meets all standards'); diff --git a/.github/workflows/publish-github-action.yml b/.github/workflows/publish-github-action.yml deleted file mode 100644 index d2789373a34..00000000000 --- a/.github/workflows/publish-github-action.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: publish-github-action - -on: - workflow_dispatch: - push: - tags: - - "github-v*.*.*" - - "!github-v1" - -concurrency: ${{ github.workflow }}-${{ github.ref }} - -permissions: - contents: write - -jobs: - publish: - runs-on: blacksmith-4vcpu-ubuntu-2404 - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - run: git fetch --force --tags - - - name: Publish - run: | - git config --global user.email "opencode@sst.dev" - git config --global user.name "opencode" - ./script/publish - working-directory: ./github diff --git a/.github/workflows/publish-vscode.yml b/.github/workflows/publish-vscode.yml deleted file mode 100644 index f49a1057807..00000000000 --- a/.github/workflows/publish-vscode.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: publish-vscode - -on: - workflow_dispatch: - push: - tags: - - "vscode-v*.*.*" - -concurrency: ${{ github.workflow }}-${{ github.ref }} - -permissions: - contents: write - -jobs: - publish: - runs-on: blacksmith-4vcpu-ubuntu-2404 - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - uses: ./.github/actions/setup-bun - - - run: git fetch --force --tags - - run: bun install -g @vscode/vsce - - - name: Install extension dependencies - run: bun install - working-directory: ./sdks/vscode - - - name: Publish - run: | - ./script/publish - working-directory: ./sdks/vscode - env: - VSCE_PAT: ${{ secrets.VSCE_PAT }} - OPENVSX_TOKEN: ${{ secrets.OPENVSX_TOKEN }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index 8d7a823b144..00000000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,237 +0,0 @@ -name: publish -run-name: "${{ format('release {0}', inputs.bump) }}" - -on: - push: - branches: - - dev - - snapshot-* - workflow_dispatch: - inputs: - bump: - description: "Bump major, minor, or patch" - required: false - type: choice - options: - - major - - minor - - patch - version: - description: "Override version (optional)" - required: false - type: string - -concurrency: ${{ github.workflow }}-${{ github.ref }}-${{ inputs.version || inputs.bump }} - -permissions: - id-token: write - contents: write - packages: write - -jobs: - publish: - runs-on: blacksmith-4vcpu-ubuntu-2404 - if: github.repository == 'anomalyco/opencode' - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - run: git fetch --force --tags - - - uses: ./.github/actions/setup-bun - - - name: Install OpenCode - if: inputs.bump || inputs.version - run: bun i -g opencode-ai@1.0.169 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - uses: actions/setup-node@v4 - with: - node-version: "24" - registry-url: "https://registry.npmjs.org" - - - name: Setup Git Identity - run: | - git config --global user.email "opencode@sst.dev" - git config --global user.name "opencode" - git remote set-url origin https://x-access-token:${{ secrets.SST_GITHUB_TOKEN }}@github.com/${{ github.repository }} - - - name: Publish - id: publish - run: ./script/publish-start.ts - env: - OPENCODE_BUMP: ${{ inputs.bump }} - OPENCODE_VERSION: ${{ inputs.version }} - OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - AUR_KEY: ${{ secrets.AUR_KEY }} - GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }} - NPM_CONFIG_PROVENANCE: false - - - uses: actions/upload-artifact@v4 - with: - name: opencode-cli - path: packages/opencode/dist - - outputs: - release: ${{ steps.publish.outputs.release }} - tag: ${{ steps.publish.outputs.tag }} - version: ${{ steps.publish.outputs.version }} - - publish-tauri: - needs: publish - continue-on-error: false - strategy: - fail-fast: false - matrix: - settings: - - host: macos-latest - target: x86_64-apple-darwin - - host: macos-latest - target: aarch64-apple-darwin - - host: blacksmith-4vcpu-windows-2025 - target: x86_64-pc-windows-msvc - - host: blacksmith-4vcpu-ubuntu-2404 - target: x86_64-unknown-linux-gnu - - host: blacksmith-4vcpu-ubuntu-2404-arm - target: aarch64-unknown-linux-gnu - runs-on: ${{ matrix.settings.host }} - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - ref: ${{ needs.publish.outputs.tag }} - - - uses: apple-actions/import-codesign-certs@v2 - if: ${{ runner.os == 'macOS' }} - with: - keychain: build - p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }} - p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - - - name: Verify Certificate - if: ${{ runner.os == 'macOS' }} - run: | - CERT_INFO=$(security find-identity -v -p codesigning build.keychain | grep "Developer ID Application") - CERT_ID=$(echo "$CERT_INFO" | awk -F'"' '{print $2}') - echo "CERT_ID=$CERT_ID" >> $GITHUB_ENV - echo "Certificate imported." - - - name: Setup Apple API Key - if: ${{ runner.os == 'macOS' }} - run: | - echo "${{ secrets.APPLE_API_KEY_PATH }}" > $RUNNER_TEMP/apple-api-key.p8 - - - run: git fetch --force --tags - - - uses: ./.github/actions/setup-bun - - - name: install dependencies (ubuntu only) - if: contains(matrix.settings.host, 'ubuntu') - run: | - sudo apt-get update - sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf - - - name: install Rust stable - uses: dtolnay/rust-toolchain@stable - with: - targets: ${{ matrix.settings.target }} - - - uses: Swatinem/rust-cache@v2 - with: - workspaces: packages/desktop/src-tauri - shared-key: ${{ matrix.settings.target }} - - - name: Prepare - run: | - cd packages/desktop - bun ./scripts/prepare.ts - env: - OPENCODE_VERSION: ${{ needs.publish.outputs.version }} - NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} - GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }} - AUR_KEY: ${{ secrets.AUR_KEY }} - OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - RUST_TARGET: ${{ matrix.settings.target }} - GH_TOKEN: ${{ github.token }} - GITHUB_RUN_ID: ${{ github.run_id }} - - # Fixes AppImage build issues, can be removed when https://github.com/tauri-apps/tauri/pull/12491 is released - - name: Install tauri-cli from portable appimage branch - if: contains(matrix.settings.host, 'ubuntu') - run: | - cargo install tauri-cli --git https://github.com/tauri-apps/tauri --branch feat/truly-portable-appimage --force - echo "Installed tauri-cli version:" - cargo tauri --version - - - name: Build and upload artifacts - uses: Wandalen/wretry.action@v3 - timeout-minutes: 60 - with: - attempt_limit: 3 - attempt_delay: 10000 - action: tauri-apps/tauri-action@390cbe447412ced1303d35abe75287949e43437a - with: | - projectPath: packages/desktop - uploadWorkflowArtifacts: true - tauriScript: ${{ (contains(matrix.settings.host, 'ubuntu') && 'cargo tauri') || '' }} - args: --target ${{ matrix.settings.target }} --config ./src-tauri/tauri.prod.conf.json --verbose - updaterJsonPreferNsis: true - releaseId: ${{ needs.publish.outputs.release }} - tagName: ${{ needs.publish.outputs.tag }} - releaseAssetNamePattern: opencode-desktop-[platform]-[arch][ext] - releaseDraft: true - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TAURI_BUNDLER_NEW_APPIMAGE_FORMAT: true - TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} - TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} - APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} - APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - APPLE_SIGNING_IDENTITY: ${{ env.CERT_ID }} - APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} - APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} - APPLE_API_KEY_PATH: ${{ runner.temp }}/apple-api-key.p8 - - publish-release: - needs: - - publish - - publish-tauri - if: needs.publish.outputs.tag - runs-on: blacksmith-4vcpu-ubuntu-2404 - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - ref: ${{ needs.publish.outputs.tag }} - - - uses: ./.github/actions/setup-bun - - - name: Setup SSH for AUR - run: | - sudo apt-get update - sudo apt-get install -y pacman-package-manager - mkdir -p ~/.ssh - echo "${{ secrets.AUR_KEY }}" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - git config --global user.email "opencode@sst.dev" - git config --global user.name "opencode" - ssh-keyscan -H aur.archlinux.org >> ~/.ssh/known_hosts || true - - - run: ./script/publish-complete.ts - env: - OPENCODE_VERSION: ${{ needs.publish.outputs.version }} - AUR_KEY: ${{ secrets.AUR_KEY }} - GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }} diff --git a/.github/workflows/release-github-action.yml b/.github/workflows/release-github-action.yml deleted file mode 100644 index 3f5caa55c8d..00000000000 --- a/.github/workflows/release-github-action.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: release-github-action - -on: - push: - branches: - - dev - paths: - - "github/**" - -concurrency: ${{ github.workflow }}-${{ github.ref }} - -permissions: - contents: write - -jobs: - release: - runs-on: blacksmith-4vcpu-ubuntu-2404 - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - run: git fetch --force --tags - - - name: Release - run: | - git config --global user.email "opencode@sst.dev" - git config --global user.name "opencode" - ./github/script/release diff --git a/.github/workflows/review.yml b/.github/workflows/review.yml deleted file mode 100644 index 93b01bafa2b..00000000000 --- a/.github/workflows/review.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: Guidelines Check - -on: - issue_comment: - types: [created] - -jobs: - check-guidelines: - if: | - github.event.issue.pull_request && - startsWith(github.event.comment.body, '/review') && - contains(fromJson('["OWNER","MEMBER"]'), github.event.comment.author_association) - runs-on: blacksmith-4vcpu-ubuntu-2404 - permissions: - contents: read - pull-requests: write - steps: - - name: Get PR number - id: pr-number - run: | - if [ "${{ github.event_name }}" = "pull_request_target" ]; then - echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT - else - echo "number=${{ github.event.issue.number }}" >> $GITHUB_OUTPUT - fi - - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - uses: ./.github/actions/setup-bun - - - name: Install opencode - run: curl -fsSL https://opencode.ai/install | bash - - - name: Get PR details - id: pr-details - run: | - gh api /repos/${{ github.repository }}/pulls/${{ steps.pr-number.outputs.number }} > pr_data.json - echo "title=$(jq -r .title pr_data.json)" >> $GITHUB_OUTPUT - echo "sha=$(jq -r .head.sha pr_data.json)" >> $GITHUB_OUTPUT - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Check PR guidelines compliance - env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - OPENCODE_PERMISSION: '{ "bash": { "*": "deny", "gh*": "allow", "gh pr review*": "deny" } }' - PR_TITLE: ${{ steps.pr-details.outputs.title }} - run: | - PR_BODY=$(jq -r .body pr_data.json) - opencode run -m anthropic/claude-opus-4-5 "A new pull request has been created: '${PR_TITLE}' - - - ${{ steps.pr-number.outputs.number }} - - - - $PR_BODY - - - Please check all the code changes in this pull request against the style guide, also look for any bugs if they exist. Diffs are important but make sure you read the entire file to get proper context. Make it clear the suggestions are merely suggestions and the human can decide what to do - - When critiquing code against the style guide, be sure that the code is ACTUALLY in violation, don't complain about else statements if they already use early returns there. You may complain about excessive nesting though, regardless of else statement usage. - When critiquing code style don't be a zealot, we don't like "let" statements but sometimes they are the simplest option, if someone does a bunch of nesting with let, they should consider using iife (see packages/opencode/src/util.iife.ts) - - Use the gh cli to create comments on the files for the violations. Try to leave the comment on the exact line number. If you have a suggested fix include it in a suggestion code block. - If you are writing suggested fixes, BE SURE THAT the change you are recommending is actually valid typescript, often I have seen missing closing "}" or other syntax errors. - Generally, write a comment instead of writing suggested change if you can help it. - - Command MUST be like this. - \`\`\` - gh api \ - --method POST \ - -H \"Accept: application/vnd.github+json\" \ - -H \"X-GitHub-Api-Version: 2022-11-28\" \ - /repos/${{ github.repository }}/pulls/${{ steps.pr-number.outputs.number }}/comments \ - -f 'body=[summary of issue]' -f 'commit_id=${{ steps.pr-details.outputs.sha }}' -f 'path=[path-to-file]' -F \"line=[line]\" -f 'side=RIGHT' - \`\`\` - - Only create comments for actual violations. If the code follows all guidelines, comment on the issue using gh cli: 'lgtm' AND NOTHING ELSE!!!!." diff --git a/.github/workflows/stale-issues.yml b/.github/workflows/stale-issues.yml deleted file mode 100644 index b5378d7d527..00000000000 --- a/.github/workflows/stale-issues.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: "Auto-close stale issues" - -on: - schedule: - - cron: "30 1 * * *" # Daily at 1:30 AM - workflow_dispatch: - -env: - DAYS_BEFORE_STALE: 90 - DAYS_BEFORE_CLOSE: 7 - -jobs: - stale: - runs-on: ubuntu-latest - permissions: - issues: write - steps: - - uses: actions/stale@v10 - with: - days-before-stale: ${{ env.DAYS_BEFORE_STALE }} - days-before-close: ${{ env.DAYS_BEFORE_CLOSE }} - stale-issue-label: "stale" - close-issue-message: | - [automated] Closing due to ${{ env.DAYS_BEFORE_STALE }}+ days of inactivity. - - Feel free to reopen if you still need this! - stale-issue-message: | - [automated] This issue has had no activity for ${{ env.DAYS_BEFORE_STALE }} days. - - It will be closed in ${{ env.DAYS_BEFORE_CLOSE }} days if there's no new activity. - remove-stale-when-updated: true - exempt-issue-labels: "pinned,security,feature-request,on-hold" - start-date: "2025-12-27" diff --git a/.github/workflows/stats.yml b/.github/workflows/stats.yml deleted file mode 100644 index 824733901d6..00000000000 --- a/.github/workflows/stats.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: stats - -on: - schedule: - - cron: "0 12 * * *" # Run daily at 12:00 UTC - workflow_dispatch: # Allow manual trigger - -concurrency: ${{ github.workflow }}-${{ github.ref }} - -jobs: - stats: - if: github.repository == 'anomalyco/opencode' - runs-on: blacksmith-4vcpu-ubuntu-2404 - permissions: - contents: write - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Bun - uses: ./.github/actions/setup-bun - - - name: Run stats script - run: bun script/stats.ts - - - name: Commit stats - run: | - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - git add STATS.md - git diff --staged --quiet || git commit -m "ignore: update download stats $(date -I)" - git push - env: - POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }} diff --git a/.github/workflows/sync-zed-extension.yml b/.github/workflows/sync-zed-extension.yml deleted file mode 100644 index f14487cde97..00000000000 --- a/.github/workflows/sync-zed-extension.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: "sync-zed-extension" - -on: - workflow_dispatch: - release: - types: [published] - -jobs: - zed: - name: Release Zed Extension - runs-on: blacksmith-4vcpu-ubuntu-2404 - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - uses: ./.github/actions/setup-bun - - - name: Get version tag - id: get_tag - run: | - if [ "${{ github.event_name }}" = "release" ]; then - TAG="${{ github.event.release.tag_name }}" - else - TAG=$(git tag --list 'v[0-9]*.*' --sort=-version:refname | head -n 1) - fi - echo "tag=${TAG}" >> $GITHUB_OUTPUT - echo "Using tag: ${TAG}" - - - name: Sync Zed extension - run: | - ./script/sync-zed.ts ${{ steps.get_tag.outputs.tag }} - env: - ZED_EXTENSIONS_PAT: ${{ secrets.ZED_EXTENSIONS_PAT }} - ZED_PR_PAT: ${{ secrets.ZED_PR_PAT }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index fcbf9569f57..00000000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,147 +0,0 @@ -name: test - -on: - push: - branches: - - dev - pull_request: - workflow_dispatch: -jobs: - test: - name: test (${{ matrix.settings.name }}) - strategy: - fail-fast: false - matrix: - settings: - - name: linux - host: blacksmith-4vcpu-ubuntu-2404 - playwright: bunx playwright install --with-deps - workdir: . - command: | - git config --global user.email "bot@opencode.ai" - git config --global user.name "opencode" - bun turbo typecheck - bun turbo test - - name: windows - host: windows-latest - playwright: bunx playwright install - workdir: packages/app - command: bun test:e2e:local - runs-on: ${{ matrix.settings.host }} - defaults: - run: - shell: bash - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Setup Bun - uses: ./.github/actions/setup-bun - - - name: Install Playwright browsers - working-directory: packages/app - run: ${{ matrix.settings.playwright }} - - - name: Set OS-specific paths - run: | - if [ "${{ runner.os }}" = "Windows" ]; then - printf '%s\n' "OPENCODE_E2E_ROOT=${{ runner.temp }}\\opencode-e2e" >> "$GITHUB_ENV" - printf '%s\n' "OPENCODE_TEST_HOME=${{ runner.temp }}\\opencode-e2e\\home" >> "$GITHUB_ENV" - printf '%s\n' "XDG_DATA_HOME=${{ runner.temp }}\\opencode-e2e\\share" >> "$GITHUB_ENV" - printf '%s\n' "XDG_CACHE_HOME=${{ runner.temp }}\\opencode-e2e\\cache" >> "$GITHUB_ENV" - printf '%s\n' "XDG_CONFIG_HOME=${{ runner.temp }}\\opencode-e2e\\config" >> "$GITHUB_ENV" - printf '%s\n' "XDG_STATE_HOME=${{ runner.temp }}\\opencode-e2e\\state" >> "$GITHUB_ENV" - printf '%s\n' "MODELS_DEV_API_JSON=${{ github.workspace }}\\packages\\opencode\\test\\tool\\fixtures\\models-api.json" >> "$GITHUB_ENV" - else - printf '%s\n' "OPENCODE_E2E_ROOT=${{ runner.temp }}/opencode-e2e" >> "$GITHUB_ENV" - printf '%s\n' "OPENCODE_TEST_HOME=${{ runner.temp }}/opencode-e2e/home" >> "$GITHUB_ENV" - printf '%s\n' "XDG_DATA_HOME=${{ runner.temp }}/opencode-e2e/share" >> "$GITHUB_ENV" - printf '%s\n' "XDG_CACHE_HOME=${{ runner.temp }}/opencode-e2e/cache" >> "$GITHUB_ENV" - printf '%s\n' "XDG_CONFIG_HOME=${{ runner.temp }}/opencode-e2e/config" >> "$GITHUB_ENV" - printf '%s\n' "XDG_STATE_HOME=${{ runner.temp }}/opencode-e2e/state" >> "$GITHUB_ENV" - printf '%s\n' "MODELS_DEV_API_JSON=${{ github.workspace }}/packages/opencode/test/tool/fixtures/models-api.json" >> "$GITHUB_ENV" - fi - - - name: Seed opencode data - if: matrix.settings.name != 'windows' - working-directory: packages/opencode - run: bun script/seed-e2e.ts - env: - MODELS_DEV_API_JSON: ${{ env.MODELS_DEV_API_JSON }} - OPENCODE_DISABLE_MODELS_FETCH: "true" - OPENCODE_DISABLE_SHARE: "true" - OPENCODE_DISABLE_LSP_DOWNLOAD: "true" - OPENCODE_DISABLE_DEFAULT_PLUGINS: "true" - OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER: "true" - OPENCODE_TEST_HOME: ${{ env.OPENCODE_TEST_HOME }} - XDG_DATA_HOME: ${{ env.XDG_DATA_HOME }} - XDG_CACHE_HOME: ${{ env.XDG_CACHE_HOME }} - XDG_CONFIG_HOME: ${{ env.XDG_CONFIG_HOME }} - XDG_STATE_HOME: ${{ env.XDG_STATE_HOME }} - OPENCODE_E2E_PROJECT_DIR: ${{ github.workspace }} - OPENCODE_E2E_SESSION_TITLE: "E2E Session" - OPENCODE_E2E_MESSAGE: "Seeded for UI e2e" - OPENCODE_E2E_MODEL: "opencode/gpt-5-nano" - - - name: Run opencode server - if: matrix.settings.name != 'windows' - working-directory: packages/opencode - run: bun dev -- --print-logs --log-level WARN serve --port 4096 --hostname 127.0.0.1 & - env: - MODELS_DEV_API_JSON: ${{ env.MODELS_DEV_API_JSON }} - OPENCODE_DISABLE_MODELS_FETCH: "true" - OPENCODE_DISABLE_SHARE: "true" - OPENCODE_DISABLE_LSP_DOWNLOAD: "true" - OPENCODE_DISABLE_DEFAULT_PLUGINS: "true" - OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER: "true" - OPENCODE_TEST_HOME: ${{ env.OPENCODE_TEST_HOME }} - XDG_DATA_HOME: ${{ env.XDG_DATA_HOME }} - XDG_CACHE_HOME: ${{ env.XDG_CACHE_HOME }} - XDG_CONFIG_HOME: ${{ env.XDG_CONFIG_HOME }} - XDG_STATE_HOME: ${{ env.XDG_STATE_HOME }} - OPENCODE_CLIENT: "app" - - - name: Wait for opencode server - if: matrix.settings.name != 'windows' - run: | - for i in {1..120}; do - curl -fsS "http://127.0.0.1:4096/global/health" > /dev/null && exit 0 - sleep 1 - done - exit 1 - - - name: run - working-directory: ${{ matrix.settings.workdir }} - run: ${{ matrix.settings.command }} - env: - CI: true - MODELS_DEV_API_JSON: ${{ env.MODELS_DEV_API_JSON }} - OPENCODE_DISABLE_MODELS_FETCH: "true" - OPENCODE_DISABLE_SHARE: "true" - OPENCODE_DISABLE_LSP_DOWNLOAD: "true" - OPENCODE_DISABLE_DEFAULT_PLUGINS: "true" - OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER: "true" - OPENCODE_TEST_HOME: ${{ env.OPENCODE_TEST_HOME }} - XDG_DATA_HOME: ${{ env.XDG_DATA_HOME }} - XDG_CACHE_HOME: ${{ env.XDG_CACHE_HOME }} - XDG_CONFIG_HOME: ${{ env.XDG_CONFIG_HOME }} - XDG_STATE_HOME: ${{ env.XDG_STATE_HOME }} - PLAYWRIGHT_SERVER_HOST: "127.0.0.1" - PLAYWRIGHT_SERVER_PORT: "4096" - VITE_OPENCODE_SERVER_HOST: "127.0.0.1" - VITE_OPENCODE_SERVER_PORT: "4096" - OPENCODE_CLIENT: "app" - timeout-minutes: 30 - - - name: Upload Playwright artifacts - if: failure() - uses: actions/upload-artifact@v4 - with: - name: playwright-${{ matrix.settings.name }}-${{ github.run_attempt }} - if-no-files-found: ignore - retention-days: 7 - path: | - packages/app/e2e/test-results - packages/app/e2e/playwright-report diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml deleted file mode 100644 index 6e150957291..00000000000 --- a/.github/workflows/triage.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Issue Triage - -on: - issues: - types: [opened] - -jobs: - triage: - runs-on: blacksmith-4vcpu-ubuntu-2404 - permissions: - contents: read - issues: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - name: Setup Bun - uses: ./.github/actions/setup-bun - - - name: Install opencode - run: curl -fsSL https://opencode.ai/install | bash - - - name: Triage issue - env: - OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ISSUE_NUMBER: ${{ github.event.issue.number }} - ISSUE_TITLE: ${{ github.event.issue.title }} - ISSUE_BODY: ${{ github.event.issue.body }} - run: | - opencode run --agent triage "The following issue was just opened, triage it: - - Title: $ISSUE_TITLE - - $ISSUE_BODY" diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml deleted file mode 100644 index 011e23f5f6f..00000000000 --- a/.github/workflows/typecheck.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: typecheck - -on: - pull_request: - branches: [dev] - workflow_dispatch: - -jobs: - typecheck: - runs-on: blacksmith-4vcpu-ubuntu-2404 - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Bun - uses: ./.github/actions/setup-bun - - - name: Run typecheck - run: bun typecheck diff --git a/.github/workflows/update-nix-hashes.yml b/.github/workflows/update-nix-hashes.yml deleted file mode 100644 index 7175f4fbdd6..00000000000 --- a/.github/workflows/update-nix-hashes.yml +++ /dev/null @@ -1,138 +0,0 @@ -name: Update Nix Hashes - -permissions: - contents: write - -on: - workflow_dispatch: - push: - paths: - - "bun.lock" - - "package.json" - - "packages/*/package.json" - - "flake.lock" - - ".github/workflows/update-nix-hashes.yml" - pull_request: - paths: - - "bun.lock" - - "package.json" - - "packages/*/package.json" - - "flake.lock" - - ".github/workflows/update-nix-hashes.yml" - -jobs: - update-node-modules-hashes: - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository - runs-on: blacksmith-4vcpu-ubuntu-2404 - env: - TITLE: node_modules hashes - - steps: - - name: Checkout repository - uses: actions/checkout@v6 - with: - token: ${{ secrets.GITHUB_TOKEN }} - fetch-depth: 0 - ref: ${{ github.head_ref || github.ref_name }} - repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} - - - name: Setup Nix - uses: nixbuild/nix-quick-install-action@v34 - - - name: Configure git - run: | - git config --global user.email "action@github.com" - git config --global user.name "Github Action" - - - name: Pull latest changes - env: - TARGET_BRANCH: ${{ github.head_ref || github.ref_name }} - run: | - BRANCH="${TARGET_BRANCH:-${GITHUB_REF_NAME}}" - git pull --rebase --autostash origin "$BRANCH" - - - name: Compute all node_modules hashes - run: | - set -euo pipefail - - HASH_FILE="nix/hashes.json" - SYSTEMS="x86_64-linux aarch64-linux x86_64-darwin aarch64-darwin" - - if [ ! -f "$HASH_FILE" ]; then - mkdir -p "$(dirname "$HASH_FILE")" - echo '{"nodeModules":{}}' > "$HASH_FILE" - fi - - for SYSTEM in $SYSTEMS; do - echo "Computing hash for ${SYSTEM}..." - BUILD_LOG=$(mktemp) - trap 'rm -f "$BUILD_LOG"' EXIT - - # The updater derivations use fakeHash, so they will fail and reveal the correct hash - UPDATER_ATTR=".#packages.x86_64-linux.${SYSTEM}_node_modules" - - nix build "$UPDATER_ATTR" --no-link 2>&1 | tee "$BUILD_LOG" || true - - CORRECT_HASH="$(grep -E 'got:\s+sha256-[A-Za-z0-9+/=]+' "$BUILD_LOG" | awk '{print $2}' | head -n1 || true)" - - if [ -z "$CORRECT_HASH" ]; then - CORRECT_HASH="$(grep -A2 'hash mismatch' "$BUILD_LOG" | grep 'got:' | awk '{print $2}' | sed 's/sha256:/sha256-/' || true)" - fi - - if [ -z "$CORRECT_HASH" ]; then - echo "Failed to determine correct node_modules hash for ${SYSTEM}." - cat "$BUILD_LOG" - exit 1 - fi - - echo " ${SYSTEM}: ${CORRECT_HASH}" - jq --arg sys "$SYSTEM" --arg h "$CORRECT_HASH" \ - '.nodeModules[$sys] = $h' "$HASH_FILE" > "${HASH_FILE}.tmp" - mv "${HASH_FILE}.tmp" "$HASH_FILE" - done - - echo "All hashes computed:" - cat "$HASH_FILE" - - - name: Commit ${{ env.TITLE }} changes - env: - TARGET_BRANCH: ${{ github.head_ref || github.ref_name }} - run: | - set -euo pipefail - - HASH_FILE="nix/hashes.json" - echo "Checking for changes..." - - summarize() { - local status="$1" - { - echo "### Nix $TITLE" - echo "" - echo "- ref: ${GITHUB_REF_NAME}" - echo "- status: ${status}" - } >> "$GITHUB_STEP_SUMMARY" - if [ -n "${GITHUB_SERVER_URL:-}" ] && [ -n "${GITHUB_REPOSITORY:-}" ] && [ -n "${GITHUB_RUN_ID:-}" ]; then - echo "- run: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" >> "$GITHUB_STEP_SUMMARY" - fi - echo "" >> "$GITHUB_STEP_SUMMARY" - } - - FILES=("$HASH_FILE") - STATUS="$(git status --short -- "${FILES[@]}" || true)" - if [ -z "$STATUS" ]; then - echo "No changes detected." - summarize "no changes" - exit 0 - fi - - echo "Changes detected:" - echo "$STATUS" - git add "${FILES[@]}" - git commit -m "chore: update nix node_modules hashes" - - BRANCH="${TARGET_BRANCH:-${GITHUB_REF_NAME}}" - git pull --rebase --autostash origin "$BRANCH" - git push origin HEAD:"$BRANCH" - echo "Changes pushed successfully" - - summarize "committed $(git rev-parse --short HEAD)" diff --git a/AGENTS.md b/AGENTS.md index 3138f6c5ece..9ea5f0fe6bf 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,4 +1,630 @@ -- To test opencode in `packages/opencode`, run `bun dev`. -- To regenerate the JavaScript SDK, run `./packages/sdk/js/script/build.ts`. -- ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE. -- The default branch in this repo is `dev`. +# Agent Guidelines for oclite + +> Lightweight fork of OpenCode by Anomaly, optimized for agentic workflows. + +**Stack:** Bun 1.3+, TypeScript, SolidJS, Tauri, Turborepo monorepo +**Default branch:** dev + +--- + +## Context7 Protocol + +**MANDATORY: Use context7 before ANY programming task.** + +``` +Before writing code: +1. Resolve library ID with context7 +2. Query documentation for current API patterns +3. Verify syntax and best practices + +Training data may be outdated. Context7 is authoritative. +``` + +When to use: Library APIs, framework patterns, configuration options, any code involving external dependencies. + +--- + +## Agent Hierarchy + +### Project Manager + +- Orchestrates work across specialists +- Delegates tasks, never executes code +- Coordinates multi-agent workflows + +### Specialists + +| Agent | Domain | Capabilities | +| ---------------------- | --------------------- | -------------------------------- | +| developer | Code implementation | Write, refactor, test code | +| git-agent | Version control | Commits, branches, PRs | +| code-review-specialist | Quality assurance | Review PRs, enforce standards | +| research-specialist | Information gathering | Research, documentation | +| adversarial-developer | Security testing | Find vulnerabilities, edge cases | +| explore | Codebase navigation | Search, understand architecture | + +### Delegation Rules + +PM delegates → Specialists execute → Report back to PM. All work traces back to GitHub issues. + +--- + +## Issue-Driven Development + +**All work must match GitHub issue content exactly.** + +```bash +# Before starting work +gh issue view #123 +``` + +Validate: Does task match issue? Am I adding unrequested features? Refuse work not explicitly listed. If scope needs expansion, update the issue first. + +--- + +## Quality Gates + +### Zero Bypasses + +**Forbidden in source code:** + +```typescript +// @ts-ignore +// @ts-expect-error +// eslint-disable +as any +``` + +If the type system complains, fix the underlying issue. + +### Zero Technical Debt + +**Forbidden in source code:** + +```typescript +// TODO +// FIXME +// HACK +// XXX +``` + +If work must be deferred, create a GitHub issue. The issue IS the TODO. + +### Style Guide Compliance + +**MANDATORY: `STYLE_GUIDE.md` is not advisory — it is a blocking requirement.** + +All code must comply with style rules. Violations are **blocking** and will fail adversarial review. No exceptions. + +**Common violation categories:** + +- No else statements — use early returns +- No destructuring — preserve context +- No let statements — use const with ternary operators +- No semicolons in code +- No type bypasses (`as any`, `@ts-ignore`, `@ts-expect-error`) +- Prefer single-word variable names +- Use Bun APIs (`Bun.file()`, `Bun.write()`) +- No `try`/`catch` where early returns suffice +- Keep functions flat and composable + +**Reference:** See the "TypeScript Style Guide" section below for detailed code examples, and `STYLE_GUIDE.md` for complete rules and rationale. + +--- + +## Pre-Push Verification + +**CI is for VERIFICATION, not DISCOVERY.** + +Before ANY `git push`, all checks must pass locally: + +```bash +# In packages/opencode directory +bun run typecheck # 0 errors (uses tsgo --noEmit) +bun test # 0 failures + +# From repo root +bun typecheck # Runs turbo typecheck across workspace +``` + +Never push to "see if CI catches anything." Fix locally first. + +--- + +## Minimalist Engineering + +**Every line of code is a liability.** + +Before creating anything: + +1. **Is this explicitly required** by the GitHub issue? +2. **Can existing code/tools** solve this instead? +3. **What's the SIMPLEST** solution? +4. **Am I building for hypothetical** future needs? + +If you cannot justify necessity, DO NOT CREATE IT. + +``` +❌ "This might be useful later" +❌ "Future-proofing" +✅ "The issue explicitly requires this" +✅ "Simplest working solution" +``` + +--- + +## Module Size Limits + +| Type | Hard Limit | Ideal | +| ------------ | ---------- | --------- | +| Source files | 500 lines | 300 lines | +| Test files | 800 lines | 500 lines | + +Refactor trigger: File exceeds 500 lines OR has 3+ distinct responsibilities. + +--- + +## Monorepo Structure + +``` +packages/ +├── opencode/ # Core CLI and TUI +├── app/ # Web UI (SolidJS) +├── desktop/ # Tauri desktop app +├── web/ # Documentation site +├── ui/ # Shared UI components +├── util/ # Shared utilities +├── sdk/js/ # JavaScript SDK +├── plugin/ # Plugin system +├── function/ # Cloud functions +├── identity/ # Auth services +├── console/ # Admin console +└── enterprise/ # Enterprise features +``` + +--- + +## Development Commands + +### From repo root + +```bash +bun install # Install all dependencies +bun typecheck # Type check entire workspace +bun dev # Run TUI (defaults to packages/opencode) +``` + +### From packages/opencode + +```bash +bun dev # Run TUI +bun dev -- serve # Headless API server (port 4096) +bun run typecheck # Type check (tsgo --noEmit) +bun test # Run tests +bun run build # Build binaries +``` + +### From packages/app + +```bash +bun dev # Start web UI dev server +bun test:e2e:local # Run Playwright E2E tests +``` + +--- + +## TypeScript Style Guide + +Reference: `STYLE_GUIDE.md` + +### Prefer const over let + +```typescript +// Good +const value = condition ? 1 : 2 + +// Bad +let value +if (condition) value = 1 +else value = 2 +``` + +### Avoid else statements + +```typescript +// Good +function process(input: string) { + if (!input) return null + return input.trim() +} +``` + +### Single word naming + +```typescript +// Good +const result = calculate(input) + +// Bad +const calculatedResult = calculate(userInput) +``` + +### Avoid destructuring + +```typescript +// Good - preserves context +console.log(user.name, user.email) + +// Bad - loses context +const { name, email } = user +``` + +### Use Bun APIs + +```typescript +// Good +const content = await Bun.file(path).text() +await Bun.write(path, content) +``` + +### Avoid any type + +```typescript +// Good +function process(data: unknown): Result { + if (isValid(data)) return transform(data) + throw new Error("Invalid data") +} +``` + +### No semicolons, minimal trailing commas + +```typescript +// Good +const config = { + name: "opencode", + version: "1.0.0", +} + +// Bad +const config = { + name: "opencode", + version: "1.0.0", +}; +``` + +--- + +## Conventional Commits + +Format: `type(scope): description` + +| Type | Use Case | +| -------- | --------------------------- | +| feat | New feature | +| fix | Bug fix | +| docs | Documentation only | +| refactor | Code change, no feature/fix | +| test | Adding or updating tests | +| chore | Maintenance tasks | +| ci | CI configuration | +| perf | Performance improvement | + +Examples: + +```bash +feat(opencode): add file watcher for hot reload +fix(app): prevent crash on empty session +refactor(util): simplify path resolution +chore: update dependencies +``` + +--- + +## Git Workflow + +### Branch Strategy + +``` +main ← production releases +dev ← active development (default) +feature/* ← feature branches +fix/* ← bug fix branches +``` + +### Standard Flow + +```bash +# 1. Create branch from dev +git checkout dev && git pull origin dev +git checkout -b feature/issue-123-description + +# 2. Implement with TDD +# Write tests → Write code → Refactor + +# 3. Verify locally +bun run typecheck && bun test + +# 4. Commit with conventional format +git add . && git commit -m "feat(opencode): implement feature (#123)" + +# 5. Push and create PR +git push -u origin feature/issue-123-description +gh pr create --base dev +``` + +--- + +## QA Workflow + +### Binary Build & Test Loop + +All feature work is validated by building and manually testing binaries. The cycle: + +``` +implement → build binary → manual QA → file bugs → fix → rebuild +``` + +### Build Commands + +```bash +# oclite (auto-installs to ~/bin/oclite with codesign) +cd packages/opencode +bun run build:lite + +# Full opencode binary +cd packages/opencode +bun run build --single +cp dist/opencode-darwin-arm64/bin/opencode ~/bin/opencode +codesign --force --deep --sign - ~/bin/opencode +xattr -cr ~/bin/opencode +``` + +### Agent Pipeline + +Every code change follows this pipeline — no exceptions: + +``` +@developer → @adversarial-developer → fix loop → @git-agent (commit+push) → rebuild binary +``` + +Never skip adversarial review. Never commit before adversarial passes. + +### Research First + +For non-trivial features, dispatch `@explore` to research how existing open-source projects solve the same problem. Clone repos to `/tmp` and analyze actual source code — don't rely on documentation alone. + +### QA Bug Tracking + +- All bugs found during QA get GitHub issues immediately +- Issues reference the specific commit and include reproduction steps +- Screenshots when applicable + +### Feature Branch Discipline + +- All work stays on the feature branch until manual QA is complete +- Push frequently — the PR is already open +- Don't merge to dev until QA passes + +--- + +## Auto-Merge Policy + +After code-review-specialist approval AND CI passes: + +- Squash merge immediately +- Delete feature branch +- Close linked issue + +Do not wait for additional approvals on reviewed PRs. + +--- + +## No Deprecated Code + +**Unreleased software has no backward compatibility requirements.** + +``` +❌ Mark as deprecated +❌ Keep for compatibility +✅ Delete old code +✅ Update all usages +``` + +When changing APIs: Find all usages → Update them → Remove old code → Single commit. + +--- + +## Testing Strategy + +### Test Organization + +``` +packages/opencode/ +├── src/feature/feature.ts +└── test/feature/feature.test.ts +``` + +### TDD Workflow + +1. Write failing test +2. Write minimal code to pass +3. Refactor +4. Repeat + +Run tests: `bun test` or `bun test --coverage` + +--- + +## Documentation Policy + +### The 200-PR Test + +Before creating documentation, ask: **"Will this be true in 200 PRs?"** + +| Answer | Action | +| ------ | ---------------------------- | +| YES | Document the principle (WHY) | +| NO | Skip or use code comments | + +**Forbidden:** Issue drafts, implementation summaries, fix notes, scratch files. + +**Allowed:** README.md, AGENTS.md, STYLE_GUIDE.md, API documentation, ADRs. + +--- + +## Error Handling + +### Prefer Result Types + +```typescript +type Result = { ok: true; value: T } | { ok: false; error: E } + +function parse(input: string): Result { + if (!input) return { ok: false, error: new Error("Empty input") } + return { ok: true, value: JSON.parse(input) } +} +``` + +### Early Returns + +```typescript +function process(data: Input) { + if (!data) return null + if (!data.valid) return null + return transform(data) +} +``` + +--- + +## Environment Variables + +### Required + +```bash +ANTHROPIC_API_KEY # For Anthropic models +OPENAI_API_KEY # For OpenAI models +``` + +### Development + +```bash +OPENCODE_TEST_HOME # Test data directory +OPENCODE_DISABLE_MODELS_FETCH # Skip model API calls +OPENCODE_DISABLE_SHARE # Disable sharing features +OPENCODE_CLIENT # Client identifier (app, cli) +``` + +--- + +## MCP Server Integration + +```json +{ + "mcpServers": { + "server-name": { + "command": "path/to/server", + "args": ["--flag"], + "env": { "API_KEY": "value" } + } + } +} +``` + +Built-in tools: File operations, shell execution, search (glob, grep), web fetch. + +--- + +## Security Guidelines + +**Never Commit:** `.env`, `*.pem`, `*.key`, `credentials.json` + +- Use environment variables for secrets +- Never hardcode API keys +- Review dependencies before adding + +--- + +## CI Workflows + +| Workflow | Trigger | Purpose | +| ------------- | ---------------- | -------------------- | +| typecheck.yml | PR | Type checking | +| test.yml | PR, push to main | Unit and E2E tests | +| review.yml | PR | Automated review | +| deploy.yml | Push to main | Deploy to production | + +Monitor with: `gh run watch [run-id]` + +--- + +## Agent Communication + +### Handoff Protocol + +1. Provide GitHub issue reference +2. Specify exact scope +3. Define success criteria +4. Request completion report + +### Status Reports + +Specialists report: What was done, what was tested, any blockers, ready for review? + +--- + +## Common Pitfalls + +``` +❌ Pushing without local verification +❌ Expanding scope beyond issue +❌ Adding "helpful" features +❌ Leaving TODO comments +❌ Using @ts-ignore +❌ Committing .env files + +✅ Local verification before push +✅ Strict issue scope adherence +✅ Minimal viable solution +✅ GitHub issues for future work +✅ Proper type definitions +✅ Environment variables for secrets +``` + +--- + +## Quick Reference + +### Before Writing Code + +```bash +# Check context7 for current documentation +gh issue view #123 +``` + +### Before Pushing + +```bash +bun run typecheck && bun test +``` + +### Before Merging + +- CI passes +- Code review approved +- Issue requirements met +- Conventional commit used + +--- + +## Summary + +1. **Use context7** before any code +2. **Follow issue scope** exactly +3. **Verify locally** before push +4. **No bypasses** or technical debt +5. **Minimalist** - every line justified +6. **Conventional commits** always +7. **Auto-merge** after approval + CI +8. **Delete** don't deprecate diff --git a/BUG_FIXES.md b/BUG_FIXES.md new file mode 100644 index 00000000000..c1837e5d159 --- /dev/null +++ b/BUG_FIXES.md @@ -0,0 +1,125 @@ +# Bug Fixes #101 and #102 + +## Summary + +Fixed two display bugs in the oclite TUI: + +1. Tools appearing inline with prose text +2. check_task tool spamming the output with repeated identical calls + +## Bug #101: Tools Render Inline with Prose + +### Problem + +Tools appeared on the same line as prose text, making output hard to read: + +``` +most impactful ones first. ◇ bash gh issue create... +``` + +### Root Cause + +When `flushLineBuffer()` was called before rendering a tool, it wrote prose text directly to stdout without ensuring the tool appeared on a new line. The `logUpdate` from liveblock would then overlay the tool on the same line. + +### Fix + +Modified `flushLineBuffer()` to accept an optional `addNewline` parameter. When flushing prose before a tool starts, a newline is added to ensure tools render on their own line. + +**File:** `packages/opencode/src/cli/lite/index.ts` + +```typescript +function flushLineBuffer(addNewline = false) { + if (!lineBuffer) return + const rendered = md.render(lineBuffer) + const wrapped = wrap(rendered, MAX_WIDTH) + write(padLines(wrapped)) + if (addNewline) write("\n") + lineBuffer = "" +} + +// Usage before tool_start +if (chunk.type === "tool_start" && chunk.tool?.trim()) { + flushLineBuffer(true) // Add newline before tool + // ... tool rendering +} +``` + +### Testing + +- Verified tools now render on separate lines from prose +- Text rendering still works correctly for regular prose chunks +- Multiple tools render on separate lines as expected + +## Bug #102: check_task Spam + +### Problem + +When a task is polled repeatedly (e.g., checking status every few seconds), the output showed the same tool ID 20+ times: + +``` +◇ check_task Checking task abc123 +◇ check_task Checking task abc123 (×2) +◇ check_task Checking task abc123 (×3) +... +``` + +### Root Cause + +The deduplication logic tracked tool names + summaries, but created new tool IDs each time (via `++toolCounter`). When polling the same task, each poll generated: + +- Same tool name (`"check_task"`) +- Same summary (task ID string) +- Same `lastToolKey` +- Different tool IDs (`check_task-1`, `check_task-2`, ...) + +Each new tool ID created a new entry in the live block, causing spam and wasting re-renders. + +### Fix + +Simplified the deduplication to maintain a single tool ID across updates. When `tool_start` is called with the same `callID` or tool key, the existing tool ID is reused and only the label is updated. + +**File:** `packages/opencode/src/cli/lite/index.ts` + +```typescript +if (chunk.type === "tool_start" && chunk.tool?.trim()) { + flushLineBuffer(true) + const tool = chunk.tool.trim() + const arg = summarizeInput(tool, chunk.input) + const summary = arg || "" + const key = `${tool}:${summary}` + + // Increment dedup count or reset for new tools + if (key === lastToolKey) { + dedupCount++ + } else { + dedupCount = 1 + lastToolKey = key + lastToolId = chunk.callID || `${tool}-${++toolCounter}` + } + + // Always update the same tool ID + const label = dedupCount > 1 ? `${summary} (×${dedupCount})` : summary + block.toolStart(lastToolId, tool, label) + // ... +} +``` + +### Testing + +- Repeated `check_task` calls for same task now show single entry +- Label increments show polling activity: `Checking task abc123 (×3)` +- Different task IDs create separate tool entries +- Non-polling tools (bash, read, etc.) unaffected + +## Verification + +All tests pass: + +```bash +cd packages/opencode +bun run typecheck # 0 errors +bun test # 1334 tests pass +bun run build:lite # Binary built and installed +``` + +Binary rebuilt and installed to `~/bin/oclite` with fixes applied. diff --git a/README.md b/README.md index 64ca1ef7a6f..d2919012c18 100644 --- a/README.md +++ b/README.md @@ -1,115 +1,125 @@ -

- - - - - OpenCode logo - - -

-

The open source AI coding agent.

-

- Discord - npm - Build status -

- -[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) +# opencode + +Opinionated AI coding agent for agentic workflows. + +> Based on [OpenCode](https://github.com/anomalyco/opencode) by Anomaly Co (MIT License) + +--- + +### What is this? + +A lightweight fork of OpenCode optimized for single developers running agentic workflows. Think PM agents orchestrating specialist agents, with deep memory/context integration via [remory](https://github.com/randomm/remory). + +**Philosophy:** + +- Opinionated defaults over endless configuration +- Optimized for agentic orchestration patterns +- Lightweight - stripped of enterprise bloat +- Single developer friendly --- ### Installation ```bash -# YOLO -curl -fsSL https://opencode.ai/install | bash - -# Package managers -npm i -g opencode-ai@latest # or bun/pnpm/yarn -scoop install opencode # Windows -choco install opencode # Windows -brew install anomalyco/tap/opencode # macOS and Linux (recommended, always up to date) -brew install opencode # macOS and Linux (official brew formula, updated less) -paru -S opencode-bin # Arch Linux -mise use -g opencode # Any OS -nix run nixpkgs#opencode # or github:anomalyco/opencode for latest dev branch +# Clone +git clone https://github.com/randomm/opencode.git +cd opencode + +# Install dependencies +bun install + +# Build +cd packages/opencode && bun run build + +# Install binary (adjust path for your platform) +cp dist/opencode-darwin-arm64/bin/opencode ~/bin/ + +# Linux x64 +# cp dist/opencode-linux-x64/bin/opencode ~/bin/ ``` -> [!TIP] -> Remove versions older than 0.1.x before installing. +Make sure `~/bin` is in your `PATH`. + +--- + +### Quick start -### Desktop App (BETA) +```bash +# Navigate to your project +cd my-project -OpenCode is also available as a desktop application. Download directly from the [releases page](https://github.com/anomalyco/opencode/releases) or [opencode.ai/download](https://opencode.ai/download). +# Start opencode +opencode +``` -| Platform | Download | -| --------------------- | ------------------------------------- | -| macOS (Apple Silicon) | `opencode-desktop-darwin-aarch64.dmg` | -| macOS (Intel) | `opencode-desktop-darwin-x64.dmg` | -| Windows | `opencode-desktop-windows-x64.exe` | -| Linux | `.deb`, `.rpm`, or AppImage | +On first run, you'll be prompted to configure your AI provider. Set your API key: ```bash -# macOS (Homebrew) -brew install --cask opencode-desktop -# Windows (Scoop) -scoop bucket add extras; scoop install extras/opencode-desktop +export ANTHROPIC_API_KEY="sk-..." +# or +export OPENAI_API_KEY="sk-..." ``` -#### Installation Directory +--- -The install script respects the following priority order for the installation path: +### Configuration -1. `$OPENCODE_INSTALL_DIR` - Custom installation directory -2. `$XDG_BIN_DIR` - XDG Base Directory Specification compliant path -3. `$HOME/bin` - Standard user binary directory (if exists or can be created) -4. `$HOME/.opencode/bin` - Default fallback +Create `opencode.json` in your project root or `~/.config/opencode/config.json` for global settings. -```bash -# Examples -OPENCODE_INSTALL_DIR=/usr/local/bin curl -fsSL https://opencode.ai/install | bash -XDG_BIN_DIR=$HOME/.local/bin curl -fsSL https://opencode.ai/install | bash +```json +{ + "provider": { + "anthropic": { + "model": "claude-sonnet-4-20250514" + } + } +} ``` -### Agents +Key options: -OpenCode includes two built-in agents you can switch between with the `Tab` key. +- `provider` - AI provider configuration (anthropic, openai, etc.) +- `mcpServers` - MCP server integrations +- `instructions` - Custom system instructions -- **build** - Default, full access agent for development work -- **plan** - Read-only agent for analysis and code exploration - - Denies file edits by default - - Asks permission before running bash commands - - Ideal for exploring unfamiliar codebases or planning changes +--- + +### Agents -Also, included is a **general** subagent for complex searches and multistep tasks. -This is used internally and can be invoked using `@general` in messages. +Two built-in agents, switchable with `Tab`: -Learn more about [agents](https://opencode.ai/docs/agents). +- **build** - Full access agent for development work (default) +- **plan** - Read-only agent for analysis and exploration -### Documentation +Use `@general` in messages to invoke the subagent for complex searches. -For more info on how to configure OpenCode [**head over to our docs**](https://opencode.ai/docs). +--- -### Contributing +### Differences from upstream -If you're interested in contributing to OpenCode, please read our [contributing docs](./CONTRIBUTING.md) before submitting a pull request. +This fork focuses on: -### Building on OpenCode +- **Agentic workflows** - Optimized for PM/specialist agent patterns +- **remory integration** - Deep memory and context management +- **Minimal footprint** - No desktop app, no VS Code extension, no npm publishing +- **Opinionated defaults** - Less configuration, more convention -If you are working on a project that's related to OpenCode and is using "opencode" as a part of its name; for example, "opencode-dashboard" or "opencode-mobile", please add a note to your README to clarify that it is not built by the OpenCode team and is not affiliated with us in any way. +Removed from upstream: -### FAQ +- Desktop application +- VS Code extension +- npm/brew/scoop publishing +- Enterprise features -#### How is this different from Claude Code? +--- -It's very similar to Claude Code in terms of capability. Here are the key differences: +### License -- 100% open source -- Not coupled to any provider. Although we recommend the models we provide through [OpenCode Zen](https://opencode.ai/zen); OpenCode can be used with Claude, OpenAI, Google or even local models. As models evolve the gaps between them will close and pricing will drop so being provider-agnostic is important. -- Out of the box LSP support -- A focus on TUI. OpenCode is built by neovim users and the creators of [terminal.shop](https://terminal.shop); we are going to push the limits of what's possible in the terminal. -- A client/server architecture. This for example can allow OpenCode to run on your computer, while you can drive it remotely from a mobile app. Meaning that the TUI frontend is just one of the possible clients. +MIT License. See [LICENSE](./LICENSE). --- -**Join our community** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode) +### Attribution + +This project is a fork of [OpenCode](https://github.com/anomalyco/opencode) by Anomaly Co, licensed under MIT. We're grateful for their work on the original project. diff --git a/RENDERING_FIXES.md b/RENDERING_FIXES.md new file mode 100644 index 00000000000..f1d861ec6af --- /dev/null +++ b/RENDERING_FIXES.md @@ -0,0 +1,90 @@ +## oclite Terminal UI Rendering Fixes + +### Changes Made to `/Users/janni/git/opencode/packages/opencode/src/cli/lite/liveblock.ts` + +#### Fix 1: Prevent Duplicate Task Tool Rendering (Line 46) + +**Before:** + +```typescript +for (const tool of tools.values()) { + const sep = tool.summary ? " " : "" + const isTask = tool.name === "task" + // ... conditional logic with isTask +} +``` + +**After:** + +```typescript +for (const tool of tools.values()) { + if (tool.name === "task") continue // Skip task tools - they're rendered separately + const sep = tool.summary ? " " : "" + // ... simplified logic without isTask +} +``` + +**Why:** Task tools were being added to both `tools` and `tasks` Maps, causing them to render twice - once in the tools loop (with ◇ icon) and once in the tasks loop (with spinner). + +#### Fix 2: Correct Multi-line Animation (Line 113) + +**Before:** + +```typescript +logUpdate(lines.join("\n") + "\n") +``` + +**After:** + +```typescript +logUpdate(lines.join("\n")) +``` + +**Why:** The `log-update` library internally adds a trailing newline (see line 140 of `node_modules/log-update/index.js`). Adding one ourselves caused incorrect line counting, making cursor positioning fail during animated updates. This resulted in only the last line being visible during animation. + +### Verification Steps + +1. **Rebuild the binary:** + + ```bash + cd /Users/janni/git/opencode/packages/opencode + bun run build:lite + ``` + +2. **Test in a real terminal (requires TTY):** + + ```bash + ~/bin/oclite 'Write hello.txt with Hello World' + ``` + +3. **Expected improvements:** + - ✅ No duplicate task tool rendering + - ✅ All lines visible during animation (not just the last one) + - ✅ Theme colors applied (green ✓, yellow spinners, dimmed gray tool names) + - ✅ Elapsed time showing on tasks: `(5s)` + - ✅ Nested child tools with indentation: ` └─ ◇ child-tool` + +### Code Details + +**Theme colors are applied in the render logic:** + +- Completed tools: `theme.tool.done.icon` = green + `theme.tool.done.text` = dim gray +- Running tools: `theme.tool.running.icon` = yellow + `theme.tool.running.text` = dim gray +- Error tools: `theme.tool.error.icon` = red + `theme.tool.error.text` = red +- Tasks: `theme.task.running.icon` = yellow + `theme.task.running.text` = cyan +- Elapsed time: `fg.gray` for the `(Xs)` text + +**Elapsed time logic (line 76):** + +```typescript +const elapsed = task.status === "running" ? Math.floor((Date.now() - task.startTime) / 1000) : task.elapsed +``` + +**Nested child tool rendering (lines 81-88):** +Only rendered when task is running and has a childTool attached, with proper indentation. + +### Testing Status + +- Binary rebuilt: ✅ +- Changes verified in code: ✅ +- Manual testing required: ⏳ (needs TTY environment) diff --git a/bun.lock b/bun.lock index 34a6488ba01..a5030b4ce8f 100644 --- a/bun.lock +++ b/bun.lock @@ -1,6 +1,6 @@ { "lockfileVersion": 1, - "configVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "opencode", @@ -180,35 +180,6 @@ "cloudflare": "5.2.0", }, }, - "packages/desktop": { - "name": "@opencode-ai/desktop", - "version": "1.1.34", - "dependencies": { - "@opencode-ai/app": "workspace:*", - "@opencode-ai/ui": "workspace:*", - "@solid-primitives/storage": "catalog:", - "@tauri-apps/api": "^2", - "@tauri-apps/plugin-dialog": "~2", - "@tauri-apps/plugin-http": "~2", - "@tauri-apps/plugin-notification": "~2", - "@tauri-apps/plugin-opener": "^2", - "@tauri-apps/plugin-os": "~2", - "@tauri-apps/plugin-process": "~2", - "@tauri-apps/plugin-shell": "~2", - "@tauri-apps/plugin-store": "~2", - "@tauri-apps/plugin-updater": "~2", - "@tauri-apps/plugin-window-state": "~2", - "solid-js": "catalog:", - }, - "devDependencies": { - "@actions/artifact": "4.0.0", - "@tauri-apps/cli": "^2", - "@types/bun": "catalog:", - "@typescript/native-preview": "catalog:", - "typescript": "~5.6.2", - "vite": "catalog:", - }, - }, "packages/enterprise": { "name": "@opencode-ai/enterprise", "version": "1.1.34", @@ -317,6 +288,7 @@ "hono-openapi": "catalog:", "ignore": "7.0.5", "jsonc-parser": "3.3.1", + "log-update": "7.0.2", "minimatch": "10.0.3", "open": "10.1.2", "opentui-spinner": "0.0.6", @@ -710,8 +682,6 @@ "@azure/core-client": ["@azure/core-client@1.10.1", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.10.0", "@azure/core-rest-pipeline": "^1.22.0", "@azure/core-tracing": "^1.3.0", "@azure/core-util": "^1.13.0", "@azure/logger": "^1.3.0", "tslib": "^2.6.2" } }, "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w=="], - "@azure/core-http": ["@azure/core-http@3.0.5", "", { "dependencies": { "@azure/abort-controller": "^1.0.0", "@azure/core-auth": "^1.3.0", "@azure/core-tracing": "1.0.0-preview.13", "@azure/core-util": "^1.1.1", "@azure/logger": "^1.0.0", "@types/node-fetch": "^2.5.0", "@types/tunnel": "^0.0.3", "form-data": "^4.0.0", "node-fetch": "^2.6.7", "process": "^0.11.10", "tslib": "^2.2.0", "tunnel": "^0.0.6", "uuid": "^8.3.0", "xml2js": "^0.5.0" } }, "sha512-T8r2q/c3DxNu6mEJfPuJtptUVqwchxzjj32gKcnMi06rdiVONS9rar7kT9T2Am+XvER7uOzpsP79WsqNbdgdWg=="], - "@azure/core-http-compat": ["@azure/core-http-compat@2.3.1", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-client": "^1.10.0", "@azure/core-rest-pipeline": "^1.22.0" } }, "sha512-az9BkXND3/d5VgdRRQVkiJb2gOmDU8Qcq4GvjtBmDICNiQ9udFmDk4ZpSB5Qq1OmtDJGlQAfBaS4palFsazQ5g=="], "@azure/core-lro": ["@azure/core-lro@2.7.2", "", { "dependencies": { "@azure/abort-controller": "^2.0.0", "@azure/core-util": "^1.2.0", "@azure/logger": "^1.0.0", "tslib": "^2.6.2" } }, "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw=="], @@ -1198,8 +1168,6 @@ "@opencode-ai/console-resource": ["@opencode-ai/console-resource@workspace:packages/console/resource"], - "@opencode-ai/desktop": ["@opencode-ai/desktop@workspace:packages/desktop"], - "@opencode-ai/enterprise": ["@opencode-ai/enterprise@workspace:packages/enterprise"], "@opencode-ai/function": ["@opencode-ai/function@workspace:packages/function"], @@ -1720,50 +1688,8 @@ "@tauri-apps/api": ["@tauri-apps/api@2.9.0", "", {}, "sha512-qD5tMjh7utwBk9/5PrTA/aGr3i5QaJ/Mlt7p8NilQ45WgbifUNPyKWsA63iQ8YfQq6R8ajMapU+/Q8nMcPRLNw=="], - "@tauri-apps/cli": ["@tauri-apps/cli@2.9.4", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.9.4", "@tauri-apps/cli-darwin-x64": "2.9.4", "@tauri-apps/cli-linux-arm-gnueabihf": "2.9.4", "@tauri-apps/cli-linux-arm64-gnu": "2.9.4", "@tauri-apps/cli-linux-arm64-musl": "2.9.4", "@tauri-apps/cli-linux-riscv64-gnu": "2.9.4", "@tauri-apps/cli-linux-x64-gnu": "2.9.4", "@tauri-apps/cli-linux-x64-musl": "2.9.4", "@tauri-apps/cli-win32-arm64-msvc": "2.9.4", "@tauri-apps/cli-win32-ia32-msvc": "2.9.4", "@tauri-apps/cli-win32-x64-msvc": "2.9.4" }, "bin": { "tauri": "tauri.js" } }, "sha512-pvylWC9QckrOS9ATWXIXcgu7g2hKK5xTL5ZQyZU/U0n9l88SEFGcWgLQNa8WZmd+wWIOWhkxOFcOl3i6ubDNNw=="], - - "@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.9.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-9rHkMVtbMhe0AliVbrGpzMahOBg3rwV46JYRELxR9SN6iu1dvPOaMaiC4cP6M/aD1424ziXnnMdYU06RAH8oIw=="], - - "@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.9.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-VT9ymNuT06f5TLjCZW2hfSxbVtZDhORk7CDUDYiq5TiSYQdxkl8MVBy0CCFFcOk4QAkUmqmVUA9r3YZ/N/vPRQ=="], - - "@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.9.4", "", { "os": "linux", "cpu": "arm" }, "sha512-tTWkEPig+2z3Rk0zqZYfjUYcgD+aSm72wdrIhdYobxbQZOBw0zfn50YtWv+av7bm0SHvv75f0l7JuwgZM1HFow=="], - - "@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-ql6vJ611qoqRYHxkKPnb2vHa27U+YRKRmIpLMMBeZnfFtZ938eao7402AQCH1mO2+/8ioUhbpy9R/ZcLTXVmkg=="], - - "@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-vg7yNn7ICTi6hRrcA/6ff2UpZQP7un3xe3SEld5QM0prgridbKAiXGaCKr3BnUBx/rGXegQlD/wiLcWdiiraSw=="], - - "@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.9.4", "", { "os": "linux", "cpu": "none" }, "sha512-l8L+3VxNk6yv5T/Z/gv5ysngmIpsai40B9p6NQQyqYqxImqYX37pqREoEBl1YwG7szGnDibpWhidPrWKR59OJA=="], - - "@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-PepPhCXc/xVvE3foykNho46OmCyx47E/aG676vKTVp+mqin5d+IBqDL6wDKiGNT5OTTxKEyNlCQ81Xs2BQhhqA=="], - - "@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-zcd1QVffh5tZs1u1SCKUV/V7RRynebgYUNWHuV0FsIF1MjnULUChEXhAhug7usCDq4GZReMJOoXa6rukEozWIw=="], - - "@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.9.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-/7ZhnP6PY04bEob23q8MH/EoDISdmR1wuNm0k9d5HV7TDMd2GGCDa8dPXA4vJuglJKXIfXqxFmZ4L+J+MO42+w=="], - - "@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.9.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-1LmAfaC4Cq+3O1Ir1ksdhczhdtFSTIV51tbAGtbV/mr348O+M52A/xwCCXQank0OcdBxy5BctqkMtuZnQvA8uQ=="], - - "@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-EdYd4c9wGvtPB95kqtEyY+bUR+k4kRw3IA30mAQ1jPH6z57AftT8q84qwv0RDp6kkEqOBKxeInKfqi4BESYuqg=="], - - "@tauri-apps/plugin-dialog": ["@tauri-apps/plugin-dialog@2.4.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-lNIn5CZuw8WZOn8zHzmFmDSzg5zfohWoa3mdULP0YFh/VogVdMVWZPcWSHlydsiJhRQYaTNSYKN7RmZKE2lCYQ=="], - - "@tauri-apps/plugin-http": ["@tauri-apps/plugin-http@2.5.4", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-/i4U/9za3mrytTgfRn5RHneKubZE/dwRmshYwyMvNRlkWjvu1m4Ma72kcbVJMZFGXpkbl+qLyWMGrihtWB76Zg=="], - - "@tauri-apps/plugin-notification": ["@tauri-apps/plugin-notification@2.3.3", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-Zw+ZH18RJb41G4NrfHgIuofJiymusqN+q8fGUIIV7vyCH+5sSn5coqRv/MWB9qETsUs97vmU045q7OyseCV3Qg=="], - - "@tauri-apps/plugin-opener": ["@tauri-apps/plugin-opener@2.5.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-ei/yRRoCklWHImwpCcDK3VhNXx+QXM9793aQ64YxpqVF0BDuuIlXhZgiAkc15wnPVav+IbkYhmDJIv5R326Mew=="], - - "@tauri-apps/plugin-os": ["@tauri-apps/plugin-os@2.3.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-n+nXWeuSeF9wcEsSPmRnBEGrRgOy6jjkSU+UVCOV8YUGKb2erhDOxis7IqRXiRVHhY8XMKks00BJ0OAdkpf6+A=="], - - "@tauri-apps/plugin-process": ["@tauri-apps/plugin-process@2.3.1", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-nCa4fGVaDL/B9ai03VyPOjfAHRHSBz5v6F/ObsB73r/dA3MHHhZtldaDMIc0V/pnUw9ehzr2iEG+XkSEyC0JJA=="], - - "@tauri-apps/plugin-shell": ["@tauri-apps/plugin-shell@2.3.3", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-Xod+pRcFxmOWFWEnqH5yZcA7qwAMuaaDkMR1Sply+F8VfBj++CGnj2xf5UoialmjZ2Cvd8qrvSCbU+7GgNVsKQ=="], - "@tauri-apps/plugin-store": ["@tauri-apps/plugin-store@2.4.1", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-ckGSEzZ5Ii4Hf2D5x25Oqnm2Zf9MfDWAzR+volY0z/OOBz6aucPKEY0F649JvQ0Vupku6UJo7ugpGRDOFOunkA=="], - "@tauri-apps/plugin-updater": ["@tauri-apps/plugin-updater@2.9.0", "", { "dependencies": { "@tauri-apps/api": "^2.6.0" } }, "sha512-j++sgY8XpeDvzImTrzWA08OqqGqgkNyxczLD7FjNJJx/uXxMZFz5nDcfkyoI/rCjYuj2101Tci/r/HFmOmoxCg=="], - - "@tauri-apps/plugin-window-state": ["@tauri-apps/plugin-window-state@2.4.1", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-OuvdrzyY8Q5Dbzpj+GcrnV1iCeoZbcFdzMjanZMMcAEUNy/6PH5pxZPXpaZLOR7whlzXiuzx0L9EKZbH7zpdRw=="], - "@thisbeyond/solid-dnd": ["@thisbeyond/solid-dnd@0.7.5", "", { "peerDependencies": { "solid-js": "^1.5" } }, "sha512-DfI5ff+yYGpK9M21LhYwIPlbP2msKxN2ARwuu6GF8tT1GgNVDTI8VCQvH4TJFoVApP9d44izmAcTh/iTCH2UUw=="], "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], @@ -1862,8 +1788,6 @@ "@types/tsscmp": ["@types/tsscmp@1.0.2", "", {}, "sha512-cy7BRSU8GYYgxjcx0Py+8lo5MthuDhlyu076KUcYzVNXL23luYgRHkMG2fIFEc6neckeh/ntP82mw+U4QjZq+g=="], - "@types/tunnel": ["@types/tunnel@0.0.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-sOUTGn6h1SfQ+gbgqC364jLFBw2lnFqkgF3q0WovEHRLMrVD1sd5aufqi/aJObLekJO+Aq5z646U4Oxy6shXMA=="], - "@types/turndown": ["@types/turndown@5.0.5", "", {}, "sha512-TL2IgGgc7B5j78rIccBtlYAnkuv8nUQqhQc+DSYV5j9Be9XOcm/SKOVRuA47xAVI3680Tk9B1d8flK2GWT2+4w=="], "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], @@ -1946,6 +1870,8 @@ "ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="], + "ansi-escapes": ["ansi-escapes@7.2.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw=="], + "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], @@ -2156,6 +2082,8 @@ "cli-boxes": ["cli-boxes@3.0.0", "", {}, "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g=="], + "cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="], + "cli-spinners": ["cli-spinners@3.3.0", "", {}, "sha512-/+40ljC3ONVnYIttjMWrlL51nItDAbBrq2upN8BPyvGU/2n5Oxw3tbNwORCaNuNqLJnxGqOfjUuhsv7l5Q4IsQ=="], "clipboardy": ["clipboardy@4.0.0", "", { "dependencies": { "execa": "^8.0.1", "is-wsl": "^3.1.0", "is64bit": "^2.0.0" } }, "sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w=="], @@ -2356,6 +2284,8 @@ "env-paths": ["env-paths@3.0.0", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="], + "environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="], + "error-stack-parser": ["error-stack-parser@2.1.4", "", { "dependencies": { "stackframe": "^1.3.4" } }, "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ=="], "error-stack-parser-es": ["error-stack-parser-es@1.0.5", "", {}, "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA=="], @@ -2746,7 +2676,7 @@ "is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="], - "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + "is-fullwidth-code-point": ["is-fullwidth-code-point@5.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.1" } }, "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ=="], "is-generator-function": ["is-generator-function@1.1.2", "", { "dependencies": { "call-bound": "^1.0.4", "generator-function": "^2.0.0", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA=="], @@ -2922,6 +2852,8 @@ "lodash.once": ["lodash.once@4.1.1", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="], + "log-update": ["log-update@7.0.2", "", { "dependencies": { "ansi-escapes": "^7.1.0", "cli-cursor": "^5.0.0", "slice-ansi": "^7.1.2", "strip-ansi": "^7.1.2", "wrap-ansi": "^9.0.2" } }, "sha512-cSSF1K5w9juI2+JeSRAdaTUZJf6cJB0aWwWO1nQQkcWw44+bIfXmhZMwK2eEsv6tXvU3UfKX/kzcX6SP+1tLAw=="], + "loglevelnext": ["loglevelnext@6.0.0", "", {}, "sha512-FDl1AI2sJGjHHG3XKJd6sG3/6ncgiGCQ0YkW46nxe7SfqQq6hujd9CvFXIXtkGBUN83KPZ2KSOJK8q5P0bSSRQ=="], "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], @@ -3090,6 +3022,8 @@ "mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="], + "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="], + "miniflare": ["miniflare@4.20251118.1", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "7.14.0", "workerd": "1.20251118.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-uLSAE/DvOm392fiaig4LOaatxLjM7xzIniFRG5Y3yF9IduOYLLK/pkCPQNCgKQH3ou0YJRHnTN+09LPfqYNTQQ=="], "minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="], @@ -3462,6 +3396,8 @@ "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + "restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="], + "restructure": ["restructure@3.0.2", "", {}, "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw=="], "retext": ["retext@9.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "retext-latin": "^4.0.0", "retext-stringify": "^4.0.0", "unified": "^11.0.0" } }, "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA=="], @@ -3562,6 +3498,8 @@ "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], + "slice-ansi": ["slice-ansi@7.1.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w=="], + "smol-toml": ["smol-toml@1.5.2", "", {}, "sha512-QlaZEqcAH3/RtNyet1IPIYPsEWAaYyXXv1Krsi+1L/QHppjX4Ifm8MQsBISz9vE8cHicIq3clogsheili5vhaQ=="], "socket.io-client": ["socket.io-client@4.8.3", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1", "engine.io-client": "~6.6.1", "socket.io-parser": "~4.2.4" } }, "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g=="], @@ -4052,14 +3990,6 @@ "@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], - "@azure/core-http/@azure/abort-controller": ["@azure/abort-controller@1.1.0", "", { "dependencies": { "tslib": "^2.2.0" } }, "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw=="], - - "@azure/core-http/@azure/core-tracing": ["@azure/core-tracing@1.0.0-preview.13", "", { "dependencies": { "@opentelemetry/api": "^1.0.1", "tslib": "^2.2.0" } }, "sha512-KxDlhXyMlh2Jhj2ykX6vNEU0Vou4nHr025KoSEiz7cS3BNiHNaZcdECk/DmLkEB0as5T7b/TpRcehJ5yV6NeXQ=="], - - "@azure/core-http/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], - - "@azure/core-http/xml2js": ["xml2js@0.5.0", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="], - "@azure/core-xml/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], @@ -4204,10 +4134,6 @@ "@openauthjs/openauth/jose": ["jose@5.9.6", "", {}, "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ=="], - "@opencode-ai/desktop/@actions/artifact": ["@actions/artifact@4.0.0", "", { "dependencies": { "@actions/core": "^1.10.0", "@actions/github": "^6.0.1", "@actions/http-client": "^2.1.0", "@azure/core-http": "^3.0.5", "@azure/storage-blob": "^12.15.0", "@octokit/core": "^5.2.1", "@octokit/plugin-request-log": "^1.0.4", "@octokit/plugin-retry": "^3.0.9", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@protobuf-ts/plugin": "^2.2.3-alpha.1", "archiver": "^7.0.1", "jwt-decode": "^3.1.2", "unzip-stream": "^0.3.1" } }, "sha512-HCc2jMJRAfviGFAh0FsOR/jNfWhirxl7W6z8zDtttt0GltwxBLdEIjLiweOPFl9WbyJRW1VWnPUSAixJqcWUMQ=="], - - "@opencode-ai/desktop/typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="], - "@opencode-ai/web/@shikijs/transformers": ["@shikijs/transformers@3.4.2", "", { "dependencies": { "@shikijs/core": "3.4.2", "@shikijs/types": "3.4.2" } }, "sha512-I5baLVi/ynLEOZoWSAMlACHNnG+yw5HDmse0oe+GW6U1u+ULdEB3UHiVWaHoJSSONV7tlcVxuaMy74sREDkSvg=="], "@opentui/solid/@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="], @@ -4452,6 +4378,8 @@ "readdir-glob/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], + "restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], + "rimraf/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], "router/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], @@ -4476,6 +4404,8 @@ "sitemap/sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="], + "slice-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "sst/aws4fetch": ["aws4fetch@1.0.18", "", {}, "sha512-3Cf+YaUl07p24MoQ46rFwulAmiyCwH2+1zw1ZyPAX5OtJ34Hh185DwB8y/qRLb6cYYYtSFJ9pthyLc0MD4e8sQ=="], @@ -4484,6 +4414,8 @@ "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "string-width-cjs/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], @@ -4576,8 +4508,6 @@ "@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], - "@azure/core-http/xml2js/sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="], - "@azure/core-xml/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], @@ -4814,8 +4744,6 @@ "@octokit/rest/@octokit/core/before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="], - "@opencode-ai/desktop/@actions/artifact/@actions/http-client": ["@actions/http-client@2.2.3", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA=="], - "@opencode-ai/web/@shikijs/transformers/@shikijs/core": ["@shikijs/core@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-AG8vnSi1W2pbgR2B911EfGqtLE9c4hQBYkv/x7Z+Kt0VxhgQKcW7UNDVYsu9YxwV6u+OJrvdJrMq6DNWoBjihQ=="], "@opencode-ai/web/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.4.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-zHC1l7L+eQlDXLnxvM9R91Efh2V4+rN3oMVS2swCBssbj2U/FBwybD1eeLaq8yl/iwT+zih8iUbTBCgGZOYlVg=="], @@ -4914,6 +4842,8 @@ "ansi-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "ansi-align/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + "ansi-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "archiver-utils/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], @@ -5062,6 +4992,8 @@ "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "wrap-ansi-cjs/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + "wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "@actions/artifact/@actions/core/@actions/exec/@actions/io": ["@actions/io@2.0.0", "", {}, "sha512-Jv33IN09XLO+0HS79aaODsvIRyduiF7NY/F6LYeK5oeUmrsz7aFdRphQjFoESF4jS7lMauDOttKALcpapVDIAg=="], @@ -5170,8 +5102,6 @@ "@octokit/rest/@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], - "@opencode-ai/desktop/@actions/artifact/@actions/http-client/undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="], - "@slack/web-api/form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], "@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es": ["oniguruma-to-es@2.3.0", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^5.1.1", "regex-recursion": "^5.1.1" } }, "sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g=="], diff --git a/packages/desktop/.gitignore b/packages/desktop/.gitignore deleted file mode 100644 index a547bf36d8d..00000000000 --- a/packages/desktop/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/packages/desktop/README.md b/packages/desktop/README.md deleted file mode 100644 index ebaf4882231..00000000000 --- a/packages/desktop/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# OpenCode Desktop - -Native OpenCode desktop app, built with Tauri v2. - -## Development - -From the repo root: - -```bash -bun install -bun run --cwd packages/desktop tauri dev -``` - -This starts the Vite dev server on http://localhost:1420 and opens the native window. - -If you only want the web dev server (no native shell): - -```bash -bun run --cwd packages/desktop dev -``` - -## Build - -To create a production `dist/` and build the native app bundle: - -```bash -bun run --cwd packages/desktop tauri build -``` - -## Prerequisites - -Running the desktop app requires additional Tauri dependencies (Rust toolchain, platform-specific libraries). See the [Tauri prerequisites](https://v2.tauri.app/start/prerequisites/) for setup instructions. diff --git a/packages/desktop/index.html b/packages/desktop/index.html deleted file mode 100644 index 6a81ef4a50d..00000000000 --- a/packages/desktop/index.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - OpenCode - - - - - - - - - - - - - -
-