diff --git a/.clinerules b/.clinerules new file mode 100644 index 00000000000..0c80b2ab3fd --- /dev/null +++ b/.clinerules @@ -0,0 +1,12 @@ +# 2026 DETERMINISTIC PROTOCOL + +## RULE 1: THE HANDSHAKE +Before you perform ANY coding task, you MUST initialize your session by calling: +selectActiveIntent(intentId: 'INT-002') +- You must strictly follow the provided in the XML response. +- Do NOT touch files outside that scope. + +## RULE 2: THE GOLDEN THREAD (LOGGING) +Every time you create, modify, or delete a file, you MUST immediately run the following hook to log the hash to the ledger: +python .orchestration/hooks/tmd.py '' '' '' +- This is mandatory for traceability. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 443842c856f..60aa5fa3337 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -3,117 +3,117 @@ description: Report a broken behavior in plain language with a minimal reproduct labels: ["bug"] title: "[BUG] " body: - - type: markdown - attributes: - value: | - Thank you for your report! Please search existing issues first: - https://github.com/RooCodeInc/Roo-Code/issues + - type: markdown + attributes: + value: | + Thank you for your report! Please search existing issues first: + https://github.com/RooCodeInc/Roo-Code/issues - - type: textarea - id: problem - attributes: - label: Problem (one or two sentences) - description: Describe what went wrong in plain language. - placeholder: 'Example: "Expected the task to start, but nothing happened and no message appeared."' - validations: - required: true + - type: textarea + id: problem + attributes: + label: Problem (one or two sentences) + description: Describe what went wrong in plain language. + placeholder: 'Example: "Expected the task to start, but nothing happened and no message appeared."' + validations: + required: true - - type: textarea - id: context - attributes: - label: Context (who is affected and when) - description: Who sees this and in what situation? Keep it non-technical. - placeholder: 'Example: "Happens to new users when starting a run from the New Run page with dark theme enabled."' - validations: - required: true + - type: textarea + id: context + attributes: + label: Context (who is affected and when) + description: Who sees this and in what situation? Keep it non-technical. + placeholder: 'Example: "Happens to new users when starting a run from the New Run page with dark theme enabled."' + validations: + required: true - - type: textarea - id: steps - attributes: - label: Reproduction steps - description: Provide clear, numbered steps so we can reproduce. - placeholder: | - 1) Environment/setup (OS, extension version, relevant settings) - 2) Exact actions (clicks, inputs, commands) - 3) What you observed after each step - validations: - required: true + - type: textarea + id: steps + attributes: + label: Reproduction steps + description: Provide clear, numbered steps so we can reproduce. + placeholder: | + 1) Environment/setup (OS, extension version, relevant settings) + 2) Exact actions (clicks, inputs, commands) + 3) What you observed after each step + validations: + required: true - - type: input - id: expected - attributes: - label: Expected result - placeholder: e.g., "The task starts and shows progress." - validations: - required: true + - type: input + id: expected + attributes: + label: Expected result + placeholder: e.g., "The task starts and shows progress." + validations: + required: true - - type: input - id: actual - attributes: - label: Actual result - placeholder: e.g., "The button appears disabled and no progress is shown." - validations: - required: true + - type: input + id: actual + attributes: + label: Actual result + placeholder: e.g., "The button appears disabled and no progress is shown." + validations: + required: true - - type: textarea - id: variations - attributes: - label: Variations tried (optional) - description: Different browsers, devices, providers, or settings you tried. - placeholder: e.g., "Tried Chrome/Firefox, disabling dark theme, switching providers." + - type: textarea + id: variations + attributes: + label: Variations tried (optional) + description: Different browsers, devices, providers, or settings you tried. + placeholder: e.g., "Tried Chrome/Firefox, disabling dark theme, switching providers." - - type: input - id: version - attributes: - label: App Version - description: What version of Roo Code are you using? (e.g., v3.3.1) - validations: - required: true + - type: input + id: version + attributes: + label: App Version + description: What version of Roo Code are you using? (e.g., v3.3.1) + validations: + required: true - - type: dropdown - id: provider - attributes: - label: API Provider (optional) - options: - - Anthropic - - Amazon Bedrock - - Chutes AI - - DeepSeek - - Featherless AI - - Fireworks AI - - Google Gemini - - Google Vertex AI - - Groq - - LiteLLM - - LM Studio - - Mistral AI - - Ollama - - OpenAI - - OpenAI Compatible - - OpenRouter - - Requesty - - SambaNova - - Unbound - - VS Code Language Model API - - xAI (Grok) - - Not Applicable / Other + - type: dropdown + id: provider + attributes: + label: API Provider (optional) + options: + - Anthropic + - Amazon Bedrock + - Chutes AI + - DeepSeek + - Featherless AI + - Fireworks AI + - Google Gemini + - Google Vertex AI + - Groq + - LiteLLM + - LM Studio + - Mistral AI + - Ollama + - OpenAI + - OpenAI Compatible + - OpenRouter + - Requesty + - SambaNova + - Unbound + - VS Code Language Model API + - xAI (Grok) + - Not Applicable / Other - - type: input - id: model - attributes: - label: Model Used (optional) - description: Exact model name (e.g., Claude 3.7 Sonnet). Use N/A if irrelevant. + - type: input + id: model + attributes: + label: Model Used (optional) + description: Exact model name (e.g., Claude 3.7 Sonnet). Use N/A if irrelevant. - - type: textarea - id: roo-code-tasks - attributes: - label: Roo Code Task Links (optional) - description: If you have any publicly shared Roo Code task links that demonstrate the issue, paste them here. - placeholder: Paste your Roo Code share links here, one per line + - type: textarea + id: roo-code-tasks + attributes: + label: Roo Code Task Links (optional) + description: If you have any publicly shared Roo Code task links that demonstrate the issue, paste them here. + placeholder: Paste your Roo Code share links here, one per line - - type: textarea - id: logs - attributes: - label: Relevant logs or errors (optional) - description: Paste relevant output or errors. Use triple backticks (```) for formatting. - render: shell + - type: textarea + id: logs + attributes: + label: Relevant logs or errors (optional) + description: Paste relevant output or errors. Use triple backticks (```) for formatting. + render: shell diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 7e140ec08cc..cb0c2434fec 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -3,89 +3,89 @@ description: Propose an improvement in plain language focused on user benefit labels: ["enhancement"] title: "[ENHANCEMENT] " body: - - type: markdown - attributes: - value: | - Thank you for helping improve Roo Code! - Please focus on the problem and the desired behavior in plain language. + - type: markdown + attributes: + value: | + Thank you for helping improve Roo Code! + Please focus on the problem and the desired behavior in plain language. - - type: textarea - id: problem - attributes: - label: Problem (one or two sentences) - description: What problem are users facing? - placeholder: e.g., "Users often click Copy Run by mistake and duplicate runs unintentionally." - validations: - required: true + - type: textarea + id: problem + attributes: + label: Problem (one or two sentences) + description: What problem are users facing? + placeholder: e.g., "Users often click Copy Run by mistake and duplicate runs unintentionally." + validations: + required: true - - type: textarea - id: context - attributes: - label: Context (who is affected and when) - description: Who encounters this and in what situation? - placeholder: e.g., "Happens when browsing the Runs list; most visible for new users." - validations: - required: true + - type: textarea + id: context + attributes: + label: Context (who is affected and when) + description: Who encounters this and in what situation? + placeholder: e.g., "Happens when browsing the Runs list; most visible for new users." + validations: + required: true - - type: textarea - id: desired - attributes: - label: Desired behavior (conceptual, not technical) - description: Describe what should happen in simple terms. - placeholder: e.g., "Ask for confirmation before copying a run." - validations: - required: true + - type: textarea + id: desired + attributes: + label: Desired behavior (conceptual, not technical) + description: Describe what should happen in simple terms. + placeholder: e.g., "Ask for confirmation before copying a run." + validations: + required: true - - type: textarea - id: constraints - attributes: - label: Constraints / preferences (optional) - description: Any considerations like performance, accessibility, or UX expectations. - placeholder: e.g., "Keep it quick and unobtrusive; keyboard accessible." + - type: textarea + id: constraints + attributes: + label: Constraints / preferences (optional) + description: Any considerations like performance, accessibility, or UX expectations. + placeholder: e.g., "Keep it quick and unobtrusive; keyboard accessible." - - type: checkboxes - id: checklist - attributes: - label: Request checklist - options: - - label: I've searched existing Issues and Discussions for duplicates - required: true - - label: This describes a specific problem with clear context and impact - required: true + - type: checkboxes + id: checklist + attributes: + label: Request checklist + options: + - label: I've searched existing Issues and Discussions for duplicates + required: true + - label: This describes a specific problem with clear context and impact + required: true - - type: textarea - id: roo-code-tasks - attributes: - label: Roo Code Task Links (optional) - description: If you explored this with Roo Code, share public task links for context. - placeholder: Paste your Roo Code share links here, one per line + - type: textarea + id: roo-code-tasks + attributes: + label: Roo Code Task Links (optional) + description: If you explored this with Roo Code, share public task links for context. + placeholder: Paste your Roo Code share links here, one per line - - type: markdown - attributes: - value: | - --- - Optional (for contributors): You can stop here if you're just proposing the improvement. + - type: markdown + attributes: + value: | + --- + Optional (for contributors): You can stop here if you're just proposing the improvement. - - type: textarea - id: acceptance-criteria - attributes: - label: Acceptance criteria (optional) - description: Define what “working” looks like with specific, testable outcomes. - placeholder: | - Given [context] - When [user action] - Then [expected result] - And [additional expectations] - But [what should NOT happen] + - type: textarea + id: acceptance-criteria + attributes: + label: Acceptance criteria (optional) + description: Define what “working” looks like with specific, testable outcomes. + placeholder: | + Given [context] + When [user action] + Then [expected result] + And [additional expectations] + But [what should NOT happen] - - type: textarea - id: proposed-solution - attributes: - label: Proposed approach (optional) - description: If you have an idea, describe it briefly in plain language. + - type: textarea + id: proposed-solution + attributes: + label: Proposed approach (optional) + description: If you have an idea, describe it briefly in plain language. - - type: textarea - id: risks - attributes: - label: Trade-offs / risks (optional) - description: Potential downsides or alternatives considered. + - type: textarea + id: risks + attributes: + label: Trade-offs / risks (optional) + description: Potential downsides or alternatives considered. diff --git a/.github/ISSUE_TEMPLATE/marketplace.yml b/.github/ISSUE_TEMPLATE/marketplace.yml index f314ca520a1..380d071300c 100644 --- a/.github/ISSUE_TEMPLATE/marketplace.yml +++ b/.github/ISSUE_TEMPLATE/marketplace.yml @@ -2,61 +2,61 @@ name: Marketplace Feedback description: Report issues or suggest improvements for marketplace items (custom modes and MCP servers) labels: ["marketplace"] body: - - type: markdown - attributes: - value: | - **Thanks for your feedback!** Please check existing issues first: https://github.com/RooCodeInc/Roo-Code/issues + - type: markdown + attributes: + value: | + **Thanks for your feedback!** Please check existing issues first: https://github.com/RooCodeInc/Roo-Code/issues - - type: dropdown - id: feedback-type - attributes: - label: What kind of feedback? - options: - - Problem with existing marketplace item - - Suggestion for new custom mode - - Suggestion for new MCP server - - General marketplace issue - validations: - required: true + - type: dropdown + id: feedback-type + attributes: + label: What kind of feedback? + options: + - Problem with existing marketplace item + - Suggestion for new custom mode + - Suggestion for new MCP server + - General marketplace issue + validations: + required: true - - type: dropdown - id: item-type - attributes: - label: Item Type (if applicable) - options: - - Custom Mode - - MCP Server - - Marketplace UI/Functionality - - Not Applicable - validations: - required: false + - type: dropdown + id: item-type + attributes: + label: Item Type (if applicable) + options: + - Custom Mode + - MCP Server + - Marketplace UI/Functionality + - Not Applicable + validations: + required: false - - type: input - id: item-name - attributes: - label: Item Name (if applicable) - placeholder: e.g., "Debug Mode", "Weather API Server", "Code Formatter" + - type: input + id: item-name + attributes: + label: Item Name (if applicable) + placeholder: e.g., "Debug Mode", "Weather API Server", "Code Formatter" - - type: textarea - id: description - attributes: - label: Description - description: What's the issue or what would you like to see? - placeholder: Clear description of the problem or suggestion - validations: - required: true + - type: textarea + id: description + attributes: + label: Description + description: What's the issue or what would you like to see? + placeholder: Clear description of the problem or suggestion + validations: + required: true - - type: textarea - id: additional-info - attributes: - label: Additional Details (optional) - description: Steps to reproduce, expected behavior, screenshots, etc. - placeholder: Any other helpful information + - type: textarea + id: additional-info + attributes: + label: Additional Details (optional) + description: Steps to reproduce, expected behavior, screenshots, etc. + placeholder: Any other helpful information - - type: checkboxes - id: checklist - attributes: - label: Checklist - options: - - label: I've searched existing issues for duplicates - required: true \ No newline at end of file + - type: checkboxes + id: checklist + attributes: + label: Checklist + options: + - label: I've searched existing issues for duplicates + required: true diff --git a/.github/actions/slack-notify/action.yml b/.github/actions/slack-notify/action.yml index 9e95ab959d3..c4571f2d3c6 100644 --- a/.github/actions/slack-notify/action.yml +++ b/.github/actions/slack-notify/action.yml @@ -1,58 +1,58 @@ -name: 'Slack Notification' -description: 'Send Slack notification for workflow failures' +name: "Slack Notification" +description: "Send Slack notification for workflow failures" inputs: - webhook-url: - description: 'Slack webhook URL' - required: true - channel: - description: 'Slack channel to notify' - required: true - workflow-name: - description: 'Name of the workflow' - required: true - failed-jobs: - description: 'JSON object containing job results' - required: true + webhook-url: + description: "Slack webhook URL" + required: true + channel: + description: "Slack channel to notify" + required: true + workflow-name: + description: "Name of the workflow" + required: true + failed-jobs: + description: "JSON object containing job results" + required: true runs: - using: 'composite' - steps: - - name: Parse failed jobs - id: parse-jobs - shell: bash - run: | - echo "Parsing job results..." - failed_list="" + using: "composite" + steps: + - name: Parse failed jobs + id: parse-jobs + shell: bash + run: | + echo "Parsing job results..." + failed_list="" - echo '${{ inputs.failed-jobs }}' | jq -r 'to_entries[] | select(.value.result == "failure") | .key' | while read job; do - case $job in - "check-translations") failed_list="${failed_list}❌ Translation check\n" ;; - "knip") failed_list="${failed_list}❌ Knip analysis\n" ;; - "compile") failed_list="${failed_list}❌ Compile & lint\n" ;; - "unit-test") failed_list="${failed_list}❌ Unit tests\n" ;; - "integration-test") failed_list="${failed_list}❌ Integration tests\n" ;; - esac - done + echo '${{ inputs.failed-jobs }}' | jq -r 'to_entries[] | select(.value.result == "failure") | .key' | while read job; do + case $job in + "check-translations") failed_list="${failed_list}❌ Translation check\n" ;; + "knip") failed_list="${failed_list}❌ Knip analysis\n" ;; + "compile") failed_list="${failed_list}❌ Compile & lint\n" ;; + "unit-test") failed_list="${failed_list}❌ Unit tests\n" ;; + "integration-test") failed_list="${failed_list}❌ Integration tests\n" ;; + esac + done - echo "failed_jobs<> $GITHUB_OUTPUT - echo -e "$failed_list" | sed '/^$/d' >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT + echo "failed_jobs<> $GITHUB_OUTPUT + echo -e "$failed_list" | sed '/^$/d' >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT - - name: Send Slack notification - uses: 8398a7/action-slack@v3 - with: - status: failure - channel: ${{ inputs.channel }} - text: | - 🚨 ${{ inputs.workflow-name }} workflow failed on main branch! + - name: Send Slack notification + uses: 8398a7/action-slack@v3 + with: + status: failure + channel: ${{ inputs.channel }} + text: | + 🚨 ${{ inputs.workflow-name }} workflow failed on main branch! - Repository: ${{ github.repository }} - Commit: ${{ github.sha }} - Author: ${{ github.actor }} + Repository: ${{ github.repository }} + Commit: ${{ github.sha }} + Author: ${{ github.actor }} - Failed jobs: - ${{ steps.parse-jobs.outputs.failed_jobs }} + Failed jobs: + ${{ steps.parse-jobs.outputs.failed_jobs }} - View details: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - env: - SLACK_WEBHOOK_URL: ${{ inputs.webhook-url }} + View details: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + env: + SLACK_WEBHOOK_URL: ${{ inputs.webhook-url }} diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5f0889ce916..955fb44860b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,7 +5,7 @@ version: 2 updates: - - package-ecosystem: "npm" # See documentation for possible values - directory: "/" # Location of package manifests - schedule: - interval: "weekly" + - package-ecosystem: "npm" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/changeset-release.yml b/.github/workflows/changeset-release.yml index 7c274b06396..9cfd9b653c0 100644 --- a/.github/workflows/changeset-release.yml +++ b/.github/workflows/changeset-release.yml @@ -2,131 +2,131 @@ name: Changeset Release run-name: Changeset Release ${{ github.actor != 'R00-B0T' && '- Create PR' || '- Update Changelog' }} on: - workflow_dispatch: - pull_request: - types: [closed, opened, labeled] + workflow_dispatch: + pull_request: + types: [closed, opened, labeled] env: - REPO_PATH: ${{ github.repository }} - GIT_REF: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || 'main' }} + REPO_PATH: ${{ github.repository }} + GIT_REF: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || 'main' }} jobs: - # Job 1: Create version bump PR when changesets are merged to main - changeset-pr-version-bump: - if: > - ( github.event_name == 'pull_request' && - github.event.pull_request.merged == true && - github.event.pull_request.base.ref == 'main' && - github.actor != 'R00-B0T' ) || - github.event_name == 'workflow_dispatch' - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - steps: - - name: Git Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: ${{ env.GIT_REF }} - - name: Setup Node.js and pnpm - uses: ./.github/actions/setup-node-pnpm + # Job 1: Create version bump PR when changesets are merged to main + changeset-pr-version-bump: + if: > + ( github.event_name == 'pull_request' && + github.event.pull_request.merged == true && + github.event.pull_request.base.ref == 'main' && + github.actor != 'R00-B0T' ) || + github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Git Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ env.GIT_REF }} + - name: Setup Node.js and pnpm + uses: ./.github/actions/setup-node-pnpm - # Check if there are any new changesets to process - - name: Check for changesets - id: check-changesets - run: | - NEW_CHANGESETS=$(find .changeset -name "*.md" ! -name "README.md" | wc -l | tr -d ' ') - echo "Changesets diff with previous version: $NEW_CHANGESETS" - echo "new_changesets=$NEW_CHANGESETS" >> $GITHUB_OUTPUT + # Check if there are any new changesets to process + - name: Check for changesets + id: check-changesets + run: | + NEW_CHANGESETS=$(find .changeset -name "*.md" ! -name "README.md" | wc -l | tr -d ' ') + echo "Changesets diff with previous version: $NEW_CHANGESETS" + echo "new_changesets=$NEW_CHANGESETS" >> $GITHUB_OUTPUT - # Create version bump PR using changesets/action if there are new changesets - - name: Changeset Pull Request - if: steps.check-changesets.outputs.new_changesets != '0' - id: changesets - uses: changesets/action@v1 - with: - commit: "changeset version bump" - title: "Changeset version bump" - version: pnpm changeset:version # This performs the changeset version bump - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Create version bump PR using changesets/action if there are new changesets + - name: Changeset Pull Request + if: steps.check-changesets.outputs.new_changesets != '0' + id: changesets + uses: changesets/action@v1 + with: + commit: "changeset version bump" + title: "Changeset version bump" + version: pnpm changeset:version # This performs the changeset version bump + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # Job 2: Process version bump PR created by R00-B0T - changeset-pr-edit-approve: - name: Auto approve and merge Bump version PRs - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - if: > - github.event_name == 'pull_request' && - github.event.pull_request.base.ref == 'main' && - github.actor == 'R00-B0T' && - contains(github.event.pull_request.title, 'Changeset version bump') - steps: - - name: Determine checkout ref - id: checkout-ref - run: | - echo "Event action: ${{ github.event.action }}" - echo "Actor: ${{ github.actor }}" - echo "Head ref: ${{ github.head_ref }}" - echo "PR SHA: ${{ github.event.pull_request.head.sha }}" + # Job 2: Process version bump PR created by R00-B0T + changeset-pr-edit-approve: + name: Auto approve and merge Bump version PRs + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + if: > + github.event_name == 'pull_request' && + github.event.pull_request.base.ref == 'main' && + github.actor == 'R00-B0T' && + contains(github.event.pull_request.title, 'Changeset version bump') + steps: + - name: Determine checkout ref + id: checkout-ref + run: | + echo "Event action: ${{ github.event.action }}" + echo "Actor: ${{ github.actor }}" + echo "Head ref: ${{ github.head_ref }}" + echo "PR SHA: ${{ github.event.pull_request.head.sha }}" - if [[ "${{ github.event.action }}" == "opened" && "${{ github.actor }}" == "R00-B0T" ]]; then - echo "Using branch ref: ${{ github.head_ref }}" - echo "git_ref=${{ github.head_ref }}" >> $GITHUB_OUTPUT - else - echo "Using SHA ref: ${{ github.event.pull_request.head.sha }}" - echo "git_ref=${{ github.event.pull_request.head.sha }}" >> $GITHUB_OUTPUT - fi + if [[ "${{ github.event.action }}" == "opened" && "${{ github.actor }}" == "R00-B0T" ]]; then + echo "Using branch ref: ${{ github.head_ref }}" + echo "git_ref=${{ github.head_ref }}" >> $GITHUB_OUTPUT + else + echo "Using SHA ref: ${{ github.event.pull_request.head.sha }}" + echo "git_ref=${{ github.event.pull_request.head.sha }}" >> $GITHUB_OUTPUT + fi - - name: Checkout Repo - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - fetch-depth: 0 - ref: ${{ steps.checkout-ref.outputs.git_ref }} + - name: Checkout Repo + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 + ref: ${{ steps.checkout-ref.outputs.git_ref }} - # Commit and push changelog updates - - name: Push Changelog updates - if: ${{ !contains(github.event.pull_request.labels.*.name, 'changelog-ready') }} - run: | - git config user.name "R00-B0T" - git config user.email github-actions@github.com - echo "Running git add and commit..." - git add CHANGELOG.md - git commit -m "Updating CHANGELOG.md format" - git status - echo "--------------------------------------------------------------------------------" - echo "Pushing to remote..." - echo "--------------------------------------------------------------------------------" - git push + # Commit and push changelog updates + - name: Push Changelog updates + if: ${{ !contains(github.event.pull_request.labels.*.name, 'changelog-ready') }} + run: | + git config user.name "R00-B0T" + git config user.email github-actions@github.com + echo "Running git add and commit..." + git add CHANGELOG.md + git commit -m "Updating CHANGELOG.md format" + git status + echo "--------------------------------------------------------------------------------" + echo "Pushing to remote..." + echo "--------------------------------------------------------------------------------" + git push - # Add label to indicate changelog has been formatted - - name: Add changelog-ready label - if: ${{ !contains(github.event.pull_request.labels.*.name, 'changelog-ready') }} - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - labels: ['changelog-ready'] - }); + # Add label to indicate changelog has been formatted + - name: Add changelog-ready label + if: ${{ !contains(github.event.pull_request.labels.*.name, 'changelog-ready') }} + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ['changelog-ready'] + }); - # Auto-approve PR only after it has been labeled - - name: Auto approve PR - if: contains(github.event.pull_request.labels.*.name, 'changelog-ready') - uses: hmarr/auto-approve-action@v4 - with: - review-message: "I'm approving since it's a bump version PR" - - # Auto-merge PR - - name: Automerge on PR - if: false # Needs enablePullRequestAutoMerge in repo settings to work contains(github.event.pull_request.labels.*.name, 'changelog-ready') - run: gh pr merge --auto --merge ${{ github.event.pull_request.number }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Auto-approve PR only after it has been labeled + - name: Auto approve PR + if: contains(github.event.pull_request.labels.*.name, 'changelog-ready') + uses: hmarr/auto-approve-action@v4 + with: + review-message: "I'm approving since it's a bump version PR" + + # Auto-merge PR + - name: Automerge on PR + if: false # Needs enablePullRequestAutoMerge in repo settings to work contains(github.event.pull_request.labels.*.name, 'changelog-ready') + run: gh pr merge --auto --merge ${{ github.event.pull_request.number }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml index 20961a9f2d3..91d5060b7f2 100644 --- a/.github/workflows/cli-release.yml +++ b/.github/workflows/cli-release.yml @@ -1,394 +1,394 @@ name: CLI Release on: - workflow_dispatch: - inputs: - version: - description: 'Version to release (e.g., 0.1.0). Leave empty to use package.json version.' - required: false - type: string - dry_run: - description: 'Dry run (build and test but do not create release).' - required: false - type: boolean - default: false + workflow_dispatch: + inputs: + version: + description: "Version to release (e.g., 0.1.0). Leave empty to use package.json version." + required: false + type: string + dry_run: + description: "Dry run (build and test but do not create release)." + required: false + type: boolean + default: false jobs: - # Build CLI for each platform. - build: - strategy: - fail-fast: false - matrix: - include: - - os: macos-latest - platform: darwin-arm64 - runs-on: macos-latest - - os: ubuntu-latest - platform: linux-x64 - runs-on: ubuntu-latest - - os: ubuntu-24.04-arm - platform: linux-arm64 - runs-on: ubuntu-24.04-arm - - runs-on: ${{ matrix.runs-on }} - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup Node.js and pnpm - uses: ./.github/actions/setup-node-pnpm - - - name: Get version - id: version - run: | - if [ -n "${{ inputs.version }}" ]; then - VERSION="${{ inputs.version }}" - else - VERSION=$(node -p "require('./apps/cli/package.json').version") - fi - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "tag=cli-v$VERSION" >> $GITHUB_OUTPUT - echo "Using version: $VERSION" - - - name: Build extension bundle - run: pnpm bundle - - - name: Build CLI - run: pnpm --filter @roo-code/cli build - - - name: Create release tarball - id: tarball - env: - VERSION: ${{ steps.version.outputs.version }} - PLATFORM: ${{ matrix.platform }} - run: | - RELEASE_DIR="roo-cli-${PLATFORM}" - TARBALL="roo-cli-${PLATFORM}.tar.gz" - - # Clean up any previous build. - rm -rf "$RELEASE_DIR" - rm -f "$TARBALL" - - # Create directory structure. - mkdir -p "$RELEASE_DIR/bin" - mkdir -p "$RELEASE_DIR/lib" - mkdir -p "$RELEASE_DIR/extension" - - # Copy CLI dist files. - echo "Copying CLI files..." - cp -r apps/cli/dist/* "$RELEASE_DIR/lib/" - - # Create package.json for npm install. - echo "Creating package.json..." - node -e " - const pkg = require('./apps/cli/package.json'); - const newPkg = { - name: '@roo-code/cli', - version: '$VERSION', - type: 'module', - dependencies: { - '@inkjs/ui': pkg.dependencies['@inkjs/ui'], - '@trpc/client': pkg.dependencies['@trpc/client'], - 'commander': pkg.dependencies.commander, - 'fuzzysort': pkg.dependencies.fuzzysort, - 'ink': pkg.dependencies.ink, - 'p-wait-for': pkg.dependencies['p-wait-for'], - 'react': pkg.dependencies.react, - 'superjson': pkg.dependencies.superjson, - 'zustand': pkg.dependencies.zustand - } - }; - console.log(JSON.stringify(newPkg, null, 2)); - " > "$RELEASE_DIR/package.json" - - # Copy extension bundle. - echo "Copying extension bundle..." - cp -r src/dist/* "$RELEASE_DIR/extension/" - - # Add package.json to extension directory for CommonJS. - echo '{"type": "commonjs"}' > "$RELEASE_DIR/extension/package.json" - - # Find and copy ripgrep binary. - echo "Looking for ripgrep binary..." - RIPGREP_PATH=$(find node_modules -path "*/@vscode/ripgrep/bin/rg" -type f 2>/dev/null | head -1) - if [ -n "$RIPGREP_PATH" ] && [ -f "$RIPGREP_PATH" ]; then - echo "Found ripgrep at: $RIPGREP_PATH" - mkdir -p "$RELEASE_DIR/node_modules/@vscode/ripgrep/bin" - cp "$RIPGREP_PATH" "$RELEASE_DIR/node_modules/@vscode/ripgrep/bin/" - chmod +x "$RELEASE_DIR/node_modules/@vscode/ripgrep/bin/rg" - mkdir -p "$RELEASE_DIR/bin" - cp "$RIPGREP_PATH" "$RELEASE_DIR/bin/" - chmod +x "$RELEASE_DIR/bin/rg" - else - echo "Warning: ripgrep binary not found" - fi - - # Create the wrapper script - echo "Creating wrapper script..." - printf '%s\n' '#!/usr/bin/env node' \ - '' \ - "import { fileURLToPath } from 'url';" \ - "import { dirname, join } from 'path';" \ - '' \ - 'const __filename = fileURLToPath(import.meta.url);' \ - 'const __dirname = dirname(__filename);' \ - '' \ - '// Set environment variables for the CLI' \ - "process.env.ROO_CLI_ROOT = join(__dirname, '..');" \ - "process.env.ROO_EXTENSION_PATH = join(__dirname, '..', 'extension');" \ - "process.env.ROO_RIPGREP_PATH = join(__dirname, 'rg');" \ - '' \ - '// Import and run the actual CLI' \ - "await import(join(__dirname, '..', 'lib', 'index.js'));" \ - > "$RELEASE_DIR/bin/roo" - - chmod +x "$RELEASE_DIR/bin/roo" - - # Create empty .env file. - touch "$RELEASE_DIR/.env" - - # Create tarball. - echo "Creating tarball..." - tar -czvf "$TARBALL" "$RELEASE_DIR" - - # Clean up release directory. - rm -rf "$RELEASE_DIR" - - # Create checksum. - if command -v sha256sum &> /dev/null; then - sha256sum "$TARBALL" > "${TARBALL}.sha256" - elif command -v shasum &> /dev/null; then - shasum -a 256 "$TARBALL" > "${TARBALL}.sha256" - fi - - echo "tarball=$TARBALL" >> $GITHUB_OUTPUT - echo "Created: $TARBALL" - ls -la "$TARBALL" - - - name: Verify tarball - env: - PLATFORM: ${{ matrix.platform }} - run: | - TARBALL="roo-cli-${PLATFORM}.tar.gz" - - # Create temp directory for verification. - VERIFY_DIR=$(mktemp -d) - - # Extract and verify structure. - tar -xzf "$TARBALL" -C "$VERIFY_DIR" - - echo "Verifying tarball contents..." - ls -la "$VERIFY_DIR/roo-cli-${PLATFORM}/" - - # Check required files exist. - test -f "$VERIFY_DIR/roo-cli-${PLATFORM}/bin/roo" || { echo "Missing bin/roo"; exit 1; } - test -f "$VERIFY_DIR/roo-cli-${PLATFORM}/lib/index.js" || { echo "Missing lib/index.js"; exit 1; } - test -f "$VERIFY_DIR/roo-cli-${PLATFORM}/package.json" || { echo "Missing package.json"; exit 1; } - test -d "$VERIFY_DIR/roo-cli-${PLATFORM}/extension" || { echo "Missing extension directory"; exit 1; } - - echo "Tarball verification passed!" - - # Cleanup. - rm -rf "$VERIFY_DIR" - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: cli-${{ matrix.platform }} - path: | - roo-cli-${{ matrix.platform }}.tar.gz - roo-cli-${{ matrix.platform }}.tar.gz.sha256 - retention-days: 7 - - # Create GitHub release with all platform artifacts. - release: - needs: build - runs-on: ubuntu-latest - if: ${{ !inputs.dry_run }} - permissions: - contents: write - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Get version - id: version - run: | - if [ -n "${{ inputs.version }}" ]; then - VERSION="${{ inputs.version }}" - else - VERSION=$(node -p "require('./apps/cli/package.json').version") - fi - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "tag=cli-v$VERSION" >> $GITHUB_OUTPUT - - - name: Download all artifacts - uses: actions/download-artifact@v4 - with: - path: artifacts - - - name: Prepare release files - run: | - mkdir -p release - find artifacts -name "*.tar.gz" -exec cp {} release/ \; - find artifacts -name "*.sha256" -exec cp {} release/ \; - ls -la release/ - - - name: Extract changelog - id: changelog - env: - VERSION: ${{ steps.version.outputs.version }} - run: | - CHANGELOG_FILE="apps/cli/CHANGELOG.md" - - if [ -f "$CHANGELOG_FILE" ]; then - # Extract content between version headers. - CONTENT=$(awk -v version="$VERSION" ' - BEGIN { found = 0; content = ""; target = "[" version "]" } - /^## \[/ { - if (found) { exit } - if (index($0, target) > 0) { found = 1; next } - } - found { content = content $0 "\n" } - END { print content } - ' "$CHANGELOG_FILE") - - if [ -n "$CONTENT" ]; then - echo "Found changelog content" - echo "content<> $GITHUB_OUTPUT - echo "$CONTENT" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - else - echo "No changelog content found for version $VERSION" - echo "content=" >> $GITHUB_OUTPUT - fi - else - echo "No changelog file found" - echo "content=" >> $GITHUB_OUTPUT - fi - - - name: Generate checksums summary - id: checksums - run: | - echo "checksums<> $GITHUB_OUTPUT - cat release/*.sha256 >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - - - name: Check for existing release - id: check_release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TAG: ${{ steps.version.outputs.tag }} - run: | - if gh release view "$TAG" &> /dev/null; then - echo "exists=true" >> $GITHUB_OUTPUT - else - echo "exists=false" >> $GITHUB_OUTPUT - fi - - - name: Delete existing release - if: steps.check_release.outputs.exists == 'true' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TAG: ${{ steps.version.outputs.tag }} - run: | - echo "Deleting existing release $TAG..." - gh release delete "$TAG" --yes || true - git push origin ":refs/tags/$TAG" || true - - - name: Create GitHub Release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - VERSION: ${{ steps.version.outputs.version }} - TAG: ${{ steps.version.outputs.tag }} - CHANGELOG_CONTENT: ${{ steps.changelog.outputs.content }} - CHECKSUMS: ${{ steps.checksums.outputs.checksums }} - run: | - NOTES_FILE=$(mktemp) - - if [ -n "$CHANGELOG_CONTENT" ]; then - echo "## What's New" >> "$NOTES_FILE" - echo "" >> "$NOTES_FILE" - echo "$CHANGELOG_CONTENT" >> "$NOTES_FILE" - echo "" >> "$NOTES_FILE" - fi - - echo "## Installation" >> "$NOTES_FILE" - echo "" >> "$NOTES_FILE" - echo '```bash' >> "$NOTES_FILE" - echo "curl -fsSL https://raw.githubusercontent.com/RooCodeInc/Roo-Code/main/apps/cli/install.sh | sh" >> "$NOTES_FILE" - echo '```' >> "$NOTES_FILE" - echo "" >> "$NOTES_FILE" - echo "Or install a specific version:" >> "$NOTES_FILE" - echo '```bash' >> "$NOTES_FILE" - echo "ROO_VERSION=$VERSION curl -fsSL https://raw.githubusercontent.com/RooCodeInc/Roo-Code/main/apps/cli/install.sh | sh" >> "$NOTES_FILE" - echo '```' >> "$NOTES_FILE" - echo "" >> "$NOTES_FILE" - echo "## Requirements" >> "$NOTES_FILE" - echo "" >> "$NOTES_FILE" - echo "- Node.js 20 or higher" >> "$NOTES_FILE" - echo "- macOS Apple Silicon (M1/M2/M3/M4), Linux x64, or Linux ARM64" >> "$NOTES_FILE" - echo "" >> "$NOTES_FILE" - echo "## Usage" >> "$NOTES_FILE" - echo "" >> "$NOTES_FILE" - echo '```bash' >> "$NOTES_FILE" - echo "# Run a task" >> "$NOTES_FILE" - echo 'roo "What is this project?"' >> "$NOTES_FILE" - echo "" >> "$NOTES_FILE" - echo "# See all options" >> "$NOTES_FILE" - echo "roo --help" >> "$NOTES_FILE" - echo '```' >> "$NOTES_FILE" - echo "" >> "$NOTES_FILE" - echo "## Platform Support" >> "$NOTES_FILE" - echo "" >> "$NOTES_FILE" - echo "This release includes binaries for:" >> "$NOTES_FILE" - echo '- `roo-cli-darwin-arm64.tar.gz` - macOS Apple Silicon (M1/M2/M3)' >> "$NOTES_FILE" - echo '- `roo-cli-linux-x64.tar.gz` - Linux x64' >> "$NOTES_FILE" - echo '- `roo-cli-linux-arm64.tar.gz` - Linux ARM64' >> "$NOTES_FILE" - echo "" >> "$NOTES_FILE" - echo "## Checksums" >> "$NOTES_FILE" - echo "" >> "$NOTES_FILE" - echo '```' >> "$NOTES_FILE" - echo "$CHECKSUMS" >> "$NOTES_FILE" - echo '```' >> "$NOTES_FILE" - - gh release create "$TAG" \ - --title "Roo Code CLI v$VERSION" \ - --notes-file "$NOTES_FILE" \ - --prerelease \ - release/* - - rm -f "$NOTES_FILE" - echo "Release created: https://github.com/${{ github.repository }}/releases/tag/$TAG" - - # Summary job for dry runs - summary: - needs: build - runs-on: ubuntu-latest - if: ${{ inputs.dry_run }} - - steps: - - name: Download all artifacts - uses: actions/download-artifact@v4 - with: - path: artifacts - - - name: Show build summary - run: | - echo "## Dry Run Complete" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "The following artifacts were built:" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - find artifacts -name "*.tar.gz" | while read f; do - SIZE=$(ls -lh "$f" | awk '{print $5}') - echo "- $(basename $f) ($SIZE)" >> $GITHUB_STEP_SUMMARY - done - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Checksums" >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY - cat artifacts/*/*.sha256 >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + # Build CLI for each platform. + build: + strategy: + fail-fast: false + matrix: + include: + - os: macos-latest + platform: darwin-arm64 + runs-on: macos-latest + - os: ubuntu-latest + platform: linux-x64 + runs-on: ubuntu-latest + - os: ubuntu-24.04-arm + platform: linux-arm64 + runs-on: ubuntu-24.04-arm + + runs-on: ${{ matrix.runs-on }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js and pnpm + uses: ./.github/actions/setup-node-pnpm + + - name: Get version + id: version + run: | + if [ -n "${{ inputs.version }}" ]; then + VERSION="${{ inputs.version }}" + else + VERSION=$(node -p "require('./apps/cli/package.json').version") + fi + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "tag=cli-v$VERSION" >> $GITHUB_OUTPUT + echo "Using version: $VERSION" + + - name: Build extension bundle + run: pnpm bundle + + - name: Build CLI + run: pnpm --filter @roo-code/cli build + + - name: Create release tarball + id: tarball + env: + VERSION: ${{ steps.version.outputs.version }} + PLATFORM: ${{ matrix.platform }} + run: | + RELEASE_DIR="roo-cli-${PLATFORM}" + TARBALL="roo-cli-${PLATFORM}.tar.gz" + + # Clean up any previous build. + rm -rf "$RELEASE_DIR" + rm -f "$TARBALL" + + # Create directory structure. + mkdir -p "$RELEASE_DIR/bin" + mkdir -p "$RELEASE_DIR/lib" + mkdir -p "$RELEASE_DIR/extension" + + # Copy CLI dist files. + echo "Copying CLI files..." + cp -r apps/cli/dist/* "$RELEASE_DIR/lib/" + + # Create package.json for npm install. + echo "Creating package.json..." + node -e " + const pkg = require('./apps/cli/package.json'); + const newPkg = { + name: '@roo-code/cli', + version: '$VERSION', + type: 'module', + dependencies: { + '@inkjs/ui': pkg.dependencies['@inkjs/ui'], + '@trpc/client': pkg.dependencies['@trpc/client'], + 'commander': pkg.dependencies.commander, + 'fuzzysort': pkg.dependencies.fuzzysort, + 'ink': pkg.dependencies.ink, + 'p-wait-for': pkg.dependencies['p-wait-for'], + 'react': pkg.dependencies.react, + 'superjson': pkg.dependencies.superjson, + 'zustand': pkg.dependencies.zustand + } + }; + console.log(JSON.stringify(newPkg, null, 2)); + " > "$RELEASE_DIR/package.json" + + # Copy extension bundle. + echo "Copying extension bundle..." + cp -r src/dist/* "$RELEASE_DIR/extension/" + + # Add package.json to extension directory for CommonJS. + echo '{"type": "commonjs"}' > "$RELEASE_DIR/extension/package.json" + + # Find and copy ripgrep binary. + echo "Looking for ripgrep binary..." + RIPGREP_PATH=$(find node_modules -path "*/@vscode/ripgrep/bin/rg" -type f 2>/dev/null | head -1) + if [ -n "$RIPGREP_PATH" ] && [ -f "$RIPGREP_PATH" ]; then + echo "Found ripgrep at: $RIPGREP_PATH" + mkdir -p "$RELEASE_DIR/node_modules/@vscode/ripgrep/bin" + cp "$RIPGREP_PATH" "$RELEASE_DIR/node_modules/@vscode/ripgrep/bin/" + chmod +x "$RELEASE_DIR/node_modules/@vscode/ripgrep/bin/rg" + mkdir -p "$RELEASE_DIR/bin" + cp "$RIPGREP_PATH" "$RELEASE_DIR/bin/" + chmod +x "$RELEASE_DIR/bin/rg" + else + echo "Warning: ripgrep binary not found" + fi + + # Create the wrapper script + echo "Creating wrapper script..." + printf '%s\n' '#!/usr/bin/env node' \ + '' \ + "import { fileURLToPath } from 'url';" \ + "import { dirname, join } from 'path';" \ + '' \ + 'const __filename = fileURLToPath(import.meta.url);' \ + 'const __dirname = dirname(__filename);' \ + '' \ + '// Set environment variables for the CLI' \ + "process.env.ROO_CLI_ROOT = join(__dirname, '..');" \ + "process.env.ROO_EXTENSION_PATH = join(__dirname, '..', 'extension');" \ + "process.env.ROO_RIPGREP_PATH = join(__dirname, 'rg');" \ + '' \ + '// Import and run the actual CLI' \ + "await import(join(__dirname, '..', 'lib', 'index.js'));" \ + > "$RELEASE_DIR/bin/roo" + + chmod +x "$RELEASE_DIR/bin/roo" + + # Create empty .env file. + touch "$RELEASE_DIR/.env" + + # Create tarball. + echo "Creating tarball..." + tar -czvf "$TARBALL" "$RELEASE_DIR" + + # Clean up release directory. + rm -rf "$RELEASE_DIR" + + # Create checksum. + if command -v sha256sum &> /dev/null; then + sha256sum "$TARBALL" > "${TARBALL}.sha256" + elif command -v shasum &> /dev/null; then + shasum -a 256 "$TARBALL" > "${TARBALL}.sha256" + fi + + echo "tarball=$TARBALL" >> $GITHUB_OUTPUT + echo "Created: $TARBALL" + ls -la "$TARBALL" + + - name: Verify tarball + env: + PLATFORM: ${{ matrix.platform }} + run: | + TARBALL="roo-cli-${PLATFORM}.tar.gz" + + # Create temp directory for verification. + VERIFY_DIR=$(mktemp -d) + + # Extract and verify structure. + tar -xzf "$TARBALL" -C "$VERIFY_DIR" + + echo "Verifying tarball contents..." + ls -la "$VERIFY_DIR/roo-cli-${PLATFORM}/" + + # Check required files exist. + test -f "$VERIFY_DIR/roo-cli-${PLATFORM}/bin/roo" || { echo "Missing bin/roo"; exit 1; } + test -f "$VERIFY_DIR/roo-cli-${PLATFORM}/lib/index.js" || { echo "Missing lib/index.js"; exit 1; } + test -f "$VERIFY_DIR/roo-cli-${PLATFORM}/package.json" || { echo "Missing package.json"; exit 1; } + test -d "$VERIFY_DIR/roo-cli-${PLATFORM}/extension" || { echo "Missing extension directory"; exit 1; } + + echo "Tarball verification passed!" + + # Cleanup. + rm -rf "$VERIFY_DIR" + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: cli-${{ matrix.platform }} + path: | + roo-cli-${{ matrix.platform }}.tar.gz + roo-cli-${{ matrix.platform }}.tar.gz.sha256 + retention-days: 7 + + # Create GitHub release with all platform artifacts. + release: + needs: build + runs-on: ubuntu-latest + if: ${{ !inputs.dry_run }} + permissions: + contents: write + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Get version + id: version + run: | + if [ -n "${{ inputs.version }}" ]; then + VERSION="${{ inputs.version }}" + else + VERSION=$(node -p "require('./apps/cli/package.json').version") + fi + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "tag=cli-v$VERSION" >> $GITHUB_OUTPUT + + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Prepare release files + run: | + mkdir -p release + find artifacts -name "*.tar.gz" -exec cp {} release/ \; + find artifacts -name "*.sha256" -exec cp {} release/ \; + ls -la release/ + + - name: Extract changelog + id: changelog + env: + VERSION: ${{ steps.version.outputs.version }} + run: | + CHANGELOG_FILE="apps/cli/CHANGELOG.md" + + if [ -f "$CHANGELOG_FILE" ]; then + # Extract content between version headers. + CONTENT=$(awk -v version="$VERSION" ' + BEGIN { found = 0; content = ""; target = "[" version "]" } + /^## \[/ { + if (found) { exit } + if (index($0, target) > 0) { found = 1; next } + } + found { content = content $0 "\n" } + END { print content } + ' "$CHANGELOG_FILE") + + if [ -n "$CONTENT" ]; then + echo "Found changelog content" + echo "content<> $GITHUB_OUTPUT + echo "$CONTENT" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + else + echo "No changelog content found for version $VERSION" + echo "content=" >> $GITHUB_OUTPUT + fi + else + echo "No changelog file found" + echo "content=" >> $GITHUB_OUTPUT + fi + + - name: Generate checksums summary + id: checksums + run: | + echo "checksums<> $GITHUB_OUTPUT + cat release/*.sha256 >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: Check for existing release + id: check_release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ steps.version.outputs.tag }} + run: | + if gh release view "$TAG" &> /dev/null; then + echo "exists=true" >> $GITHUB_OUTPUT + else + echo "exists=false" >> $GITHUB_OUTPUT + fi + + - name: Delete existing release + if: steps.check_release.outputs.exists == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ steps.version.outputs.tag }} + run: | + echo "Deleting existing release $TAG..." + gh release delete "$TAG" --yes || true + git push origin ":refs/tags/$TAG" || true + + - name: Create GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ steps.version.outputs.version }} + TAG: ${{ steps.version.outputs.tag }} + CHANGELOG_CONTENT: ${{ steps.changelog.outputs.content }} + CHECKSUMS: ${{ steps.checksums.outputs.checksums }} + run: | + NOTES_FILE=$(mktemp) + + if [ -n "$CHANGELOG_CONTENT" ]; then + echo "## What's New" >> "$NOTES_FILE" + echo "" >> "$NOTES_FILE" + echo "$CHANGELOG_CONTENT" >> "$NOTES_FILE" + echo "" >> "$NOTES_FILE" + fi + + echo "## Installation" >> "$NOTES_FILE" + echo "" >> "$NOTES_FILE" + echo '```bash' >> "$NOTES_FILE" + echo "curl -fsSL https://raw.githubusercontent.com/RooCodeInc/Roo-Code/main/apps/cli/install.sh | sh" >> "$NOTES_FILE" + echo '```' >> "$NOTES_FILE" + echo "" >> "$NOTES_FILE" + echo "Or install a specific version:" >> "$NOTES_FILE" + echo '```bash' >> "$NOTES_FILE" + echo "ROO_VERSION=$VERSION curl -fsSL https://raw.githubusercontent.com/RooCodeInc/Roo-Code/main/apps/cli/install.sh | sh" >> "$NOTES_FILE" + echo '```' >> "$NOTES_FILE" + echo "" >> "$NOTES_FILE" + echo "## Requirements" >> "$NOTES_FILE" + echo "" >> "$NOTES_FILE" + echo "- Node.js 20 or higher" >> "$NOTES_FILE" + echo "- macOS Apple Silicon (M1/M2/M3/M4), Linux x64, or Linux ARM64" >> "$NOTES_FILE" + echo "" >> "$NOTES_FILE" + echo "## Usage" >> "$NOTES_FILE" + echo "" >> "$NOTES_FILE" + echo '```bash' >> "$NOTES_FILE" + echo "# Run a task" >> "$NOTES_FILE" + echo 'roo "What is this project?"' >> "$NOTES_FILE" + echo "" >> "$NOTES_FILE" + echo "# See all options" >> "$NOTES_FILE" + echo "roo --help" >> "$NOTES_FILE" + echo '```' >> "$NOTES_FILE" + echo "" >> "$NOTES_FILE" + echo "## Platform Support" >> "$NOTES_FILE" + echo "" >> "$NOTES_FILE" + echo "This release includes binaries for:" >> "$NOTES_FILE" + echo '- `roo-cli-darwin-arm64.tar.gz` - macOS Apple Silicon (M1/M2/M3)' >> "$NOTES_FILE" + echo '- `roo-cli-linux-x64.tar.gz` - Linux x64' >> "$NOTES_FILE" + echo '- `roo-cli-linux-arm64.tar.gz` - Linux ARM64' >> "$NOTES_FILE" + echo "" >> "$NOTES_FILE" + echo "## Checksums" >> "$NOTES_FILE" + echo "" >> "$NOTES_FILE" + echo '```' >> "$NOTES_FILE" + echo "$CHECKSUMS" >> "$NOTES_FILE" + echo '```' >> "$NOTES_FILE" + + gh release create "$TAG" \ + --title "Roo Code CLI v$VERSION" \ + --notes-file "$NOTES_FILE" \ + --prerelease \ + release/* + + rm -f "$NOTES_FILE" + echo "Release created: https://github.com/${{ github.repository }}/releases/tag/$TAG" + + # Summary job for dry runs + summary: + needs: build + runs-on: ubuntu-latest + if: ${{ inputs.dry_run }} + + steps: + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Show build summary + run: | + echo "## Dry Run Complete" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "The following artifacts were built:" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + find artifacts -name "*.tar.gz" | while read f; do + SIZE=$(ls -lh "$f" | awk '{print $5}') + echo "- $(basename $f) ($SIZE)" >> $GITHUB_STEP_SUMMARY + done + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Checksums" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + cat artifacts/*/*.sha256 >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 0784c8cbad0..1c064c2f308 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,81 +1,81 @@ name: CodeQL Advanced on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - schedule: - - cron: '24 19 * * 3' + push: + branches: ["main"] + pull_request: + branches: ["main"] + schedule: + - cron: "24 19 * * 3" jobs: - analyze: - name: Analyze (${{ matrix.language }}) - # Runner size impacts CodeQL analysis time. To learn more, please see: - # - https://gh.io/recommended-hardware-resources-for-running-codeql - # - https://gh.io/supported-runners-and-hardware-resources - # - https://gh.io/using-larger-runners (GitHub.com only) - # Consider using larger runners or machines with greater resources for possible analysis time improvements. - runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} - permissions: - # required for all workflows - security-events: write + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + permissions: + # required for all workflows + security-events: write - # required to fetch internal or private CodeQL packs - packages: read + # required to fetch internal or private CodeQL packs + packages: read - # only required for workflows in private repositories - actions: read - contents: read + # only required for workflows in private repositories + actions: read + contents: read - strategy: - fail-fast: false - matrix: - include: - - language: javascript-typescript - build-mode: none - # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' - # Use `c-cpp` to analyze code written in C, C++ or both - # Use 'java-kotlin' to analyze code written in Java, Kotlin or both - # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both - # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, - # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. - # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how - # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages - steps: - - name: Checkout repository - uses: actions/checkout@v4 + strategy: + fail-fast: false + matrix: + include: + - language: javascript-typescript + build-mode: none + # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + steps: + - name: Checkout repository + uses: actions/checkout@v4 - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - build-mode: ${{ matrix.build-mode }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. - # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality - # If the analyze step fails for one of the languages you are analyzing with - # "We were unable to automatically build your code", modify the matrix above - # to set the build mode to "manual" for that language. Then modify this step - # to build your code. - # ℹ️ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - if: matrix.build-mode == 'manual' - shell: bash - run: | - echo 'If you are using a "manual" build mode for one or more of the' \ - 'languages you are analyzing, replace this with the commands to build' \ - 'your code, for example:' - echo ' make bootstrap' - echo ' make release' - exit 1 + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - with: - category: "/language:${{matrix.language}}" + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/marketplace-publish.yml b/.github/workflows/marketplace-publish.yml index aef91b2d323..7e42c4e6844 100644 --- a/.github/workflows/marketplace-publish.yml +++ b/.github/workflows/marketplace-publish.yml @@ -1,92 +1,92 @@ name: Publish Extension on: - pull_request: - types: [closed] - workflow_dispatch: + pull_request: + types: [closed] + workflow_dispatch: env: - GIT_REF: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || 'main' }} + GIT_REF: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || 'main' }} jobs: - publish-extension: - runs-on: ubuntu-latest - permissions: - contents: write # Required for pushing tags. - if: > - ( github.event_name == 'pull_request' && - github.event.pull_request.base.ref == 'main' && - contains(github.event.pull_request.title, 'Changeset version bump') ) || - github.event_name == 'workflow_dispatch' - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ env.GIT_REF }} - - name: Setup Node.js and pnpm - uses: ./.github/actions/setup-node-pnpm - - name: Configure Git - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - name: Create .env file - run: echo "POSTHOG_API_KEY=${{ secrets.POSTHOG_API_KEY }}" >> .env - - name: Package Extension - run: | - current_package_version=$(node -p "require('./src/package.json').version") - pnpm vsix + publish-extension: + runs-on: ubuntu-latest + permissions: + contents: write # Required for pushing tags. + if: > + ( github.event_name == 'pull_request' && + github.event.pull_request.base.ref == 'main' && + contains(github.event.pull_request.title, 'Changeset version bump') ) || + github.event_name == 'workflow_dispatch' + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ env.GIT_REF }} + - name: Setup Node.js and pnpm + uses: ./.github/actions/setup-node-pnpm + - name: Configure Git + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + - name: Create .env file + run: echo "POSTHOG_API_KEY=${{ secrets.POSTHOG_API_KEY }}" >> .env + - name: Package Extension + run: | + current_package_version=$(node -p "require('./src/package.json').version") + pnpm vsix - # Save VSIX contents to a temporary file to avoid broken pipe issues. - unzip -l bin/roo-cline-${current_package_version}.vsix > /tmp/roo-code-vsix-contents.txt + # Save VSIX contents to a temporary file to avoid broken pipe issues. + unzip -l bin/roo-cline-${current_package_version}.vsix > /tmp/roo-code-vsix-contents.txt - # Check for required files. - grep -q "extension/package.json" /tmp/roo-code-vsix-contents.txt || exit 1 - grep -q "extension/package.nls.json" /tmp/roo-code-vsix-contents.txt || exit 1 - grep -q "extension/dist/extension.js" /tmp/roo-code-vsix-contents.txt || exit 1 - grep -q "extension/webview-ui/audio/celebration.wav" /tmp/roo-code-vsix-contents.txt || exit 1 - grep -q "extension/webview-ui/build/assets/index.js" /tmp/roo-code-vsix-contents.txt || exit 1 - grep -q "extension/assets/codicons/codicon.ttf" /tmp/roo-code-vsix-contents.txt || exit 1 - grep -q "extension/assets/vscode-material-icons/icons/3d.svg" /tmp/roo-code-vsix-contents.txt || exit 1 - grep -q ".env" /tmp/roo-code-vsix-contents.txt || exit 1 - - # Clean up temporary file. - rm /tmp/roo-code-vsix-contents.txt - - name: Create and Push Git Tag - run: | - current_package_version=$(node -p "require('./src/package.json').version") - git tag -a "v${current_package_version}" -m "Release v${current_package_version}" - git push origin "v${current_package_version}" --no-verify - echo "Successfully created and pushed git tag v${current_package_version}" - - name: Publish Extension - env: - VSCE_PAT: ${{ secrets.VSCE_PAT }} - OVSX_PAT: ${{ secrets.OVSX_PAT }} - run: | - current_package_version=$(node -p "require('./src/package.json').version") - pnpm --filter roo-cline publish:marketplace - echo "Successfully published version $current_package_version to VS Code Marketplace" - - name: Create GitHub Release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - current_package_version=$(node -p "require('./src/package.json').version") + # Check for required files. + grep -q "extension/package.json" /tmp/roo-code-vsix-contents.txt || exit 1 + grep -q "extension/package.nls.json" /tmp/roo-code-vsix-contents.txt || exit 1 + grep -q "extension/dist/extension.js" /tmp/roo-code-vsix-contents.txt || exit 1 + grep -q "extension/webview-ui/audio/celebration.wav" /tmp/roo-code-vsix-contents.txt || exit 1 + grep -q "extension/webview-ui/build/assets/index.js" /tmp/roo-code-vsix-contents.txt || exit 1 + grep -q "extension/assets/codicons/codicon.ttf" /tmp/roo-code-vsix-contents.txt || exit 1 + grep -q "extension/assets/vscode-material-icons/icons/3d.svg" /tmp/roo-code-vsix-contents.txt || exit 1 + grep -q ".env" /tmp/roo-code-vsix-contents.txt || exit 1 - # Extract changelog for current version - echo "Extracting changelog for version ${current_package_version}" - changelog_content=$(sed -n "/## \\[${current_package_version}\\]/,/## \\[/p" CHANGELOG.md | sed '$d') + # Clean up temporary file. + rm /tmp/roo-code-vsix-contents.txt + - name: Create and Push Git Tag + run: | + current_package_version=$(node -p "require('./src/package.json').version") + git tag -a "v${current_package_version}" -m "Release v${current_package_version}" + git push origin "v${current_package_version}" --no-verify + echo "Successfully created and pushed git tag v${current_package_version}" + - name: Publish Extension + env: + VSCE_PAT: ${{ secrets.VSCE_PAT }} + OVSX_PAT: ${{ secrets.OVSX_PAT }} + run: | + current_package_version=$(node -p "require('./src/package.json').version") + pnpm --filter roo-cline publish:marketplace + echo "Successfully published version $current_package_version to VS Code Marketplace" + - name: Create GitHub Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + current_package_version=$(node -p "require('./src/package.json').version") - # If changelog extraction failed, use a default message - if [ -z "$changelog_content" ]; then - echo "Warning: No changelog section found for version ${current_package_version}" - changelog_content="Release v${current_package_version}" - else - echo "Found changelog section for version ${current_package_version}" - fi + # Extract changelog for current version + echo "Extracting changelog for version ${current_package_version}" + changelog_content=$(sed -n "/## \\[${current_package_version}\\]/,/## \\[/p" CHANGELOG.md | sed '$d') - # Create release with changelog content - gh release create "v${current_package_version}" \ - --title "Release v${current_package_version}" \ - --notes "$changelog_content" \ - --target ${{ env.GIT_REF }} \ - bin/roo-cline-${current_package_version}.vsix - echo "Successfully created GitHub Release v${current_package_version}" + # If changelog extraction failed, use a default message + if [ -z "$changelog_content" ]; then + echo "Warning: No changelog section found for version ${current_package_version}" + changelog_content="Release v${current_package_version}" + else + echo "Found changelog section for version ${current_package_version}" + fi + + # Create release with changelog content + gh release create "v${current_package_version}" \ + --title "Release v${current_package_version}" \ + --notes "$changelog_content" \ + --target ${{ env.GIT_REF }} \ + bin/roo-cline-${current_package_version}.vsix + echo "Successfully created GitHub Release v${current_package_version}" diff --git a/.github/workflows/nightly-publish.yml b/.github/workflows/nightly-publish.yml index e25bdba990a..79a67d17058 100644 --- a/.github/workflows/nightly-publish.yml +++ b/.github/workflows/nightly-publish.yml @@ -1,52 +1,52 @@ name: Nightly Publish on: - push: - branches: [main] - workflow_dispatch: # Allows manual triggering. + push: + branches: [main] + workflow_dispatch: # Allows manual triggering. jobs: - publish-nightly: - runs-on: ubuntu-latest + publish-nightly: + runs-on: ubuntu-latest - permissions: - contents: read # No tags pushed → read is enough. + permissions: + contents: read # No tags pushed → read is enough. - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Setup Node.js and pnpm - uses: ./.github/actions/setup-node-pnpm - with: - install-args: '--frozen-lockfile' - - name: Forge numeric Nightly version - id: version - env: - RUN_NUMBER: ${{ github.run_number }} - run: echo "number=$(( 5500 + ${RUN_NUMBER} ))" >> $GITHUB_OUTPUT - - name: Patch package.json version - env: - VERSION_NUMBER: ${{ steps.version.outputs.number }} - run: | - node <<'EOF' - const fs = require('fs'); - const path = require('path'); - const pkgPath = path.join(__dirname, 'apps', 'vscode-nightly', 'package.nightly.json'); - const pkg = JSON.parse(fs.readFileSync(pkgPath,'utf8')); - const [maj, min] = pkg.version.split('.'); - pkg.version = `${maj}.${min}.${process.env.VERSION_NUMBER}`; - fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2)); - console.log(`🔖 Nightly version set to ${pkg.version}`); - EOF - - name: Build VSIX - run: pnpm vsix:nightly # Produces bin/roo-code-nightly-0.0.[count].vsix - - name: Publish to VS Code Marketplace - env: - VSCE_PAT: ${{ secrets.VSCE_PAT }} - run: npx vsce publish --packagePath "bin/$(/bin/ls bin | head -n1)" - - name: Publish to Open VSX Registry - env: - OVSX_PAT: ${{ secrets.OVSX_PAT }} - run: npx ovsx publish "bin/$(ls bin | head -n1)" + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Setup Node.js and pnpm + uses: ./.github/actions/setup-node-pnpm + with: + install-args: "--frozen-lockfile" + - name: Forge numeric Nightly version + id: version + env: + RUN_NUMBER: ${{ github.run_number }} + run: echo "number=$(( 5500 + ${RUN_NUMBER} ))" >> $GITHUB_OUTPUT + - name: Patch package.json version + env: + VERSION_NUMBER: ${{ steps.version.outputs.number }} + run: | + node <<'EOF' + const fs = require('fs'); + const path = require('path'); + const pkgPath = path.join(__dirname, 'apps', 'vscode-nightly', 'package.nightly.json'); + const pkg = JSON.parse(fs.readFileSync(pkgPath,'utf8')); + const [maj, min] = pkg.version.split('.'); + pkg.version = `${maj}.${min}.${process.env.VERSION_NUMBER}`; + fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2)); + console.log(`🔖 Nightly version set to ${pkg.version}`); + EOF + - name: Build VSIX + run: pnpm vsix:nightly # Produces bin/roo-code-nightly-0.0.[count].vsix + - name: Publish to VS Code Marketplace + env: + VSCE_PAT: ${{ secrets.VSCE_PAT }} + run: npx vsce publish --packagePath "bin/$(/bin/ls bin | head -n1)" + - name: Publish to Open VSX Registry + env: + OVSX_PAT: ${{ secrets.OVSX_PAT }} + run: npx ovsx publish "bin/$(ls bin | head -n1)" diff --git a/.github/workflows/update-contributors.yml b/.github/workflows/update-contributors.yml index 5709bdc10a0..c7a79627255 100644 --- a/.github/workflows/update-contributors.yml +++ b/.github/workflows/update-contributors.yml @@ -1,67 +1,67 @@ name: Update Contributors # Refresh contrib.rocks image cache on: - workflow_dispatch: + workflow_dispatch: permissions: - contents: write - pull-requests: write + contents: write + pull-requests: write jobs: - refresh-contrib-cache: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 + refresh-contrib-cache: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 - - name: Bump cacheBust in all README files - run: | - set -euo pipefail - TS="$(date +%s)" - # Target only the root README.md and localized READMEs under locales/*/README.md - mapfile -t FILES < <(git ls-files README.md 'locales/*/README.md' || true) + - name: Bump cacheBust in all README files + run: | + set -euo pipefail + TS="$(date +%s)" + # Target only the root README.md and localized READMEs under locales/*/README.md + mapfile -t FILES < <(git ls-files README.md 'locales/*/README.md' || true) - if [ "${#FILES[@]}" -eq 0 ]; then - echo "No target README files found." >&2 - exit 1 - fi + if [ "${#FILES[@]}" -eq 0 ]; then + echo "No target README files found." >&2 + exit 1 + fi - UPDATED=0 - for f in "${FILES[@]}"; do - if grep -q 'cacheBust=' "$f"; then - # Use portable sed in GNU environment of ubuntu-latest - sed -i -E "s/cacheBust=[0-9]+/cacheBust=${TS}/g" "$f" - echo "Updated cacheBust in $f" - UPDATED=1 - else - echo "Warning: cacheBust parameter not found in $f" >&2 - fi - done + UPDATED=0 + for f in "${FILES[@]}"; do + if grep -q 'cacheBust=' "$f"; then + # Use portable sed in GNU environment of ubuntu-latest + sed -i -E "s/cacheBust=[0-9]+/cacheBust=${TS}/g" "$f" + echo "Updated cacheBust in $f" + UPDATED=1 + else + echo "Warning: cacheBust parameter not found in $f" >&2 + fi + done - if [ "$UPDATED" -eq 0 ]; then - echo "No files were updated. Ensure READMEs embed contrib.rocks with cacheBust param." >&2 - exit 1 - fi + if [ "$UPDATED" -eq 0 ]; then + echo "No files were updated. Ensure READMEs embed contrib.rocks with cacheBust param." >&2 + exit 1 + fi - - name: Detect changes - id: changes - run: | - if git diff --quiet; then - echo "changed=false" >> $GITHUB_OUTPUT - else - echo "changed=true" >> $GITHUB_OUTPUT - fi + - name: Detect changes + id: changes + run: | + if git diff --quiet; then + echo "changed=false" >> $GITHUB_OUTPUT + else + echo "changed=true" >> $GITHUB_OUTPUT + fi - - name: Create Pull Request - if: steps.changes.outputs.changed == 'true' - uses: peter-evans/create-pull-request@v7 - with: - token: ${{ secrets.GITHUB_TOKEN }} - commit-message: "docs: update contributors list [skip ci]" - committer: "github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>" - branch: refresh-contrib-cache - delete-branch: true - title: "Refresh contrib.rocks image cache (all READMEs)" - body: | - Automated refresh of the contrib.rocks image cache by bumping the cacheBust parameter in README.md and locales/*/README.md. - base: main + - name: Create Pull Request + if: steps.changes.outputs.changed == 'true' + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "docs: update contributors list [skip ci]" + committer: "github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>" + branch: refresh-contrib-cache + delete-branch: true + title: "Refresh contrib.rocks image cache (all READMEs)" + body: | + Automated refresh of the contrib.rocks image cache by bumping the cacheBust parameter in README.md and locales/*/README.md. + base: main diff --git a/.github/workflows/website-deploy.yml b/.github/workflows/website-deploy.yml index da2d4228f51..77f13fdaebb 100644 --- a/.github/workflows/website-deploy.yml +++ b/.github/workflows/website-deploy.yml @@ -5,7 +5,7 @@ on: branches: - main paths: - - 'apps/web-roo-code/**' + - "apps/web-roo-code/**" workflow_dispatch: concurrency: @@ -25,11 +25,11 @@ jobs: - name: Check if VERCEL_TOKEN exists id: check run: | - if [ -n "${{ secrets.VERCEL_TOKEN }}" ]; then - echo "has-vercel-token=true" >> $GITHUB_OUTPUT - else - echo "has-vercel-token=false" >> $GITHUB_OUTPUT - fi + if [ -n "${{ secrets.VERCEL_TOKEN }}" ]; then + echo "has-vercel-token=true" >> $GITHUB_OUTPUT + else + echo "has-vercel-token=false" >> $GITHUB_OUTPUT + fi deploy: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 1dbcdc6a362..2b89d7931f3 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,7 @@ AGENTS.local.md # Test environment .test_env .vscode-test/ - +.venv/ # Docs docs/_site/ @@ -55,3 +55,15 @@ qdrant_storage/ plans/ roo-cli-*.tar.gz* + + +# VS Code MCP analytics file — do not commit +.vscode/mcp.json + +# --- Orchestration Sidecar (Phase 1) --- +# We commit the .yaml spec and .py hooks, but NEVER the local data +.orchestration/*.db +.orchestration/*.db-journal +.orchestration/*.db-wal +.orchestration/zvec_store/ +.orchestration/agent_trace.jsonl \ No newline at end of file diff --git a/.intentignore b/.intentignore new file mode 100644 index 00000000000..a2ada1d8be7 --- /dev/null +++ b/.intentignore @@ -0,0 +1,10 @@ +# GLOBAL SECURITY BOUNDARY +.env +.git/ +node_modules/ +.orchestration/trace_storage.db +.clinerules + +# INTENT-SPECIFIC PROTECTION +# Prevents the AI from modifying the core orchestration logic +.orchestration/hooks/ diff --git a/.nvmrc b/.nvmrc index 1d898f1fe56..cc5a0f33065 100644 Binary files a/.nvmrc and b/.nvmrc differ diff --git a/.orchestration/active_intents.yaml b/.orchestration/active_intents.yaml new file mode 100644 index 00000000000..bbc106c1bd4 --- /dev/null +++ b/.orchestration/active_intents.yaml @@ -0,0 +1,15 @@ +active_intents: + - id: "INT-001" + name: "Initialize TRACE Governance" + status: "COMPLETED" + owned_scope: ["src/hooks/**"] + # ... other fields ... + + - id: "INT-002" + name: "Refactor Auth Middleware" + status: "IN_PROGRESS" + owned_scope: ["src/auth/**", "src/middleware/jwt.ts"] + constraints: + - "Must maintain backward compatibility with Basic Auth" + acceptance_criteria: + - "JWT rotation tests pass" \ No newline at end of file diff --git a/.orchestration/agent_trace.jsonl b/.orchestration/agent_trace.jsonl new file mode 100644 index 00000000000..f7c7bedcee8 --- /dev/null +++ b/.orchestration/agent_trace.jsonl @@ -0,0 +1 @@ +{"id": "init-uuid", "timestamp": "2026-02-16T12:00:00Z", "intent_id": "INT-001", "vcs": { "revision_id": "initial" }, "files": [{"relative_path": "src/hooks/Gatekeeper.ts", "conversations": [{"url": "init_session", "contributor": {"entity_type": "AI", "model_identifier": "claude-3-5-sonnet"}, "ranges": [{"start_line": 1, "end_line": 1, "content_hash": "sha256:0000000"}]}]}]}{"mutation_class":"INTENT_EVOLUTION","timestamp":"2026-02-20T19:57:01Z","content_hash":"f3d8ec89f06e5a685faba375e55a2115aaab6ba51a6ef2ff336a6415d079c2f4","related_reqs":["REQ-001"],"file_path":".orchestration/phase2_check.txt","intent_id":"INT-002"} diff --git a/.orchestration/hooks/init_zvec.py b/.orchestration/hooks/init_zvec.py new file mode 100644 index 00000000000..e0c0a30e169 --- /dev/null +++ b/.orchestration/hooks/init_zvec.py @@ -0,0 +1,34 @@ +import sqlite3 +import os + +# Logic: Define the path for our Sidecar DB +db_path = os.path.join(".orchestration", "trace_storage.db") + +def init_db(): + try: + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + + # Logic: Create the table for your Agent Traces (Phase 1 Data Model) + cursor.execute(''' + CREATE TABLE IF NOT EXISTS agent_traces ( + id TEXT PRIMARY KEY, + timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, + intent_id TEXT, + file_path TEXT, + content_hash TEXT, + metadata TEXT + ) + ''') + + # Logic: Optimization for low RAM - use Disk as Virtual RAM + cursor.execute("PRAGMA mmap_size = 268435456;") # 256MB mmap + + conn.commit() + conn.close() + print(f"✅ Orchestration Ledger Initialized at {db_path}") + except Exception as e: + print(f"❌ Error: {e}") + +if __name__ == "__main__": + init_db() \ No newline at end of file diff --git a/.orchestration/hooks/tmd.py b/.orchestration/hooks/tmd.py new file mode 100644 index 00000000000..4fbdba06f17 --- /dev/null +++ b/.orchestration/hooks/tmd.py @@ -0,0 +1,43 @@ +import hashlib +import sqlite3 +import sys +import os +import uuid + +# Logic: Maintain consistent pathing for Windows/Linux +BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +DB_PATH = os.path.join(BASE_DIR, ".orchestration", "trace_storage.db") + +def calculate_sha256(content): + """Normalized hashing: ignores whitespace and line endings to ensure + consistency across different editors/OS.""" + normalized = "".join(content.split()).encode('utf-8') + return hashlib.sha256(normalized).hexdigest() + +def log_change(intent_id, file_path, content): + content_hash = calculate_sha256(content) + trace_id = str(uuid.uuid4()) + + try: + conn = sqlite3.connect(DB_PATH) + # Performance: Use Write-Ahead Logging for faster disk I/O + conn.execute("PRAGMA journal_mode=WAL;") + cursor = conn.cursor() + cursor.execute(''' + INSERT INTO agent_traces (id, intent_id, file_path, content_hash) + VALUES (?, ?, ?, ?) + ''', (trace_id, intent_id, file_path, content_hash)) + conn.commit() + conn.close() + return content_hash + except Exception as e: + return f"Database Error: {e}" + +if __name__ == "__main__": + # Command: python tmd.py + if len(sys.argv) >= 4: + intent, path, code = sys.argv[1], sys.argv[2], sys.argv[3] + result_hash = log_change(intent, path, code) + print(f"HASH_VERIFIED:{result_hash}") + else: + print("Usage: python tmd.py ") \ No newline at end of file diff --git a/.orchestration/intent_map.md b/.orchestration/intent_map.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/.orchestration/phase2_check.txt b/.orchestration/phase2_check.txt new file mode 100644 index 00000000000..8188953562e --- /dev/null +++ b/.orchestration/phase2_check.txt @@ -0,0 +1 @@ +Human edited this first! diff --git a/.orchestration/security_policy.json b/.orchestration/security_policy.json new file mode 100644 index 00000000000..ec4079b38a7 --- /dev/null +++ b/.orchestration/security_policy.json @@ -0,0 +1,11 @@ +{ + "version": "1.0.0", + "command_classification": { + "safe": ["read_file", "list_files", "search_files"], + "destructive": ["write_to_file", "delete_file", "execute_command"] + }, + "error_protocol": { + "type": "JSON_TOOL_ERROR", + "template": "Scope Violation: {intent_id} is not authorized to edit {file}. Request scope expansion." + } +} diff --git a/.roo/commands/roo-resolve-conflicts.md b/.roo/commands/roo-resolve-conflicts.md index 4a3a80bdd34..38b2038658c 100644 --- a/.roo/commands/roo-resolve-conflicts.md +++ b/.roo/commands/roo-resolve-conflicts.md @@ -11,10 +11,10 @@ Resolve merge conflicts for a specific pull request by analyzing git history, co 1. **Provide a PR number** (e.g., `#123` or just `123`) 2. The workflow will automatically: - - Fetch PR information (title, description, branches) - - Checkout the PR branch - - Rebase onto the target branch to reveal conflicts - - Analyze and resolve conflicts using git history + - Fetch PR information (title, description, branches) + - Checkout the PR branch + - Rebase onto the target branch to reveal conflicts + - Analyze and resolve conflicts using git history ## Workflow Steps @@ -39,6 +39,7 @@ git status --porcelain | grep "^UU" ### 3. Analyze Each Conflict For each conflicted file: + - Read the conflict markers - Run `git blame` on conflicting sections - Fetch commit messages for context @@ -47,6 +48,7 @@ For each conflicted file: ### 4. Apply Resolution Strategy Based on the analysis: + - **Bugfixes** generally take precedence over features - **Recent changes** are often more relevant (unless older is a security fix) - **Combine** non-conflicting changes when possible diff --git a/.roo/commands/roo-translate.md b/.roo/commands/roo-translate.md index 3f974948946..28a8dc67c84 100644 --- a/.roo/commands/roo-translate.md +++ b/.roo/commands/roo-translate.md @@ -9,32 +9,35 @@ Perform translation and localization tasks for the Roo Code extension. This comm ## Quick Start 1. **Identify the translation scope:** - - If a specific language code is provided (e.g., `de`, `zh-CN`), focus on that language - - If `all` is specified, translate to all supported languages - - If a string key is provided, locate and translate that specific string - - If a file path is provided, work with that translation file + + - If a specific language code is provided (e.g., `de`, `zh-CN`), focus on that language + - If `all` is specified, translate to all supported languages + - If a string key is provided, locate and translate that specific string + - If a file path is provided, work with that translation file 2. **Supported languages:** ca, de, en, es, fr, hi, id, it, ja, ko, nl, pl, pt-BR, ru, tr, vi, zh-CN, zh-TW 3. **Translation locations:** - - Core Extension: `src/i18n/locales/` - - WebView UI: `webview-ui/src/i18n/locales/` + - Core Extension: `src/i18n/locales/` + - WebView UI: `webview-ui/src/i18n/locales/` ## Workflow 1. If adding new strings: - - Add the English string first - - Ask for confirmation before translating to other languages - - Use `apply_diff` for efficient file updates + + - Add the English string first + - Ask for confirmation before translating to other languages + - Use `apply_diff` for efficient file updates 2. If updating existing strings: - - Identify all affected language files - - Update English first, then propagate changes + + - Identify all affected language files + - Update English first, then propagate changes 3. Validate your changes: - ```bash - node scripts/find-missing-translations.js - ``` + ```bash + node scripts/find-missing-translations.js + ``` ## Key Guidelines diff --git a/.roo/rules-deepseek-code/instructions.txt b/.roo/rules-deepseek-code/instructions.txt new file mode 100644 index 00000000000..8c7355d3b76 --- /dev/null +++ b/.roo/rules-deepseek-code/instructions.txt @@ -0,0 +1,17 @@ +TOOL EXECUTION RULES (CRITICAL): + +Always use Roo tools when interacting with the workspace. + +After EVERY tool call, you MUST provide a short confirmation message describing the result before continuing. + +Workflow: +1. Call ONE tool at a time. +2. Wait for the result. +3. Briefly summarize the result. +4. Then decide the next action. + +Never call multiple tools in one response. +Never end a response immediately after a tool call. +Always include a short natural-language confirmation after tool usage. + +Prefer small sequential actions over complex plans. diff --git a/.roo/skills/roo-conflict-resolution/SKILL.md b/.roo/skills/roo-conflict-resolution/SKILL.md index 7b123a8107b..4807180522f 100644 --- a/.roo/skills/roo-conflict-resolution/SKILL.md +++ b/.roo/skills/roo-conflict-resolution/SKILL.md @@ -105,16 +105,16 @@ Verify the resolution and prepare for commit: ## Git Commands Reference -| Command | Purpose | -|---------|---------| -| `gh pr checkout [PR_NUMBER] --force` | Force checkout the PR branch | -| `git fetch origin main` | Get the latest main branch | -| `GIT_EDITOR=true git rebase origin/main` | Rebase current branch onto main (non-interactive) | -| `git blame -L [start],[end] [commit] -- [file]` | Get commit information for specific lines | -| `git show --format="%H%n%an%n%ae%n%ad%n%s%n%b" --no-patch [sha]` | Get commit metadata | -| `git show [sha] -- [file]` | Get the actual changes made in a commit | -| `git ls-files -u` | List unmerged files with stage information | -| `GIT_EDITOR=true git rebase --continue` | Continue rebase after resolving conflicts | +| Command | Purpose | +| ---------------------------------------------------------------- | ------------------------------------------------- | +| `gh pr checkout [PR_NUMBER] --force` | Force checkout the PR branch | +| `git fetch origin main` | Get the latest main branch | +| `GIT_EDITOR=true git rebase origin/main` | Rebase current branch onto main (non-interactive) | +| `git blame -L [start],[end] [commit] -- [file]` | Get commit information for specific lines | +| `git show --format="%H%n%an%n%ae%n%ad%n%s%n%b" --no-patch [sha]` | Get commit metadata | +| `git show [sha] -- [file]` | Get the actual changes made in a commit | +| `git ls-files -u` | List unmerged files with stage information | +| `GIT_EDITOR=true git rebase --continue` | Continue rebase after resolving conflicts | ## Best Practices @@ -141,12 +141,12 @@ Look beyond the immediate conflict to understand related changes in tests, docum ## Resolution Heuristics -| Category | Rule | Exception | -|----------|------|-----------| -| Bugfix vs Feature | Bugfixes generally take precedence | When features include the fix | -| Recent vs Old | More recent changes are often more relevant | When older changes are security patches | -| Test Updates | Changes with test updates are likely more complete | - | -| Formatting vs Logic | Logic changes take precedence over formatting | - | +| Category | Rule | Exception | +| ------------------- | -------------------------------------------------- | --------------------------------------- | +| Bugfix vs Feature | Bugfixes generally take precedence | When features include the fix | +| Recent vs Old | More recent changes are often more relevant | When older changes are security patches | +| Test Updates | Changes with test updates are likely more complete | - | +| Formatting vs Logic | Logic changes take precedence over formatting | - | ## Common Pitfalls diff --git a/.roo/skills/roo-translation/SKILL.md b/.roo/skills/roo-translation/SKILL.md index 2660e39ba90..dafffb78c97 100644 --- a/.roo/skills/roo-translation/SKILL.md +++ b/.roo/skills/roo-translation/SKILL.md @@ -29,10 +29,10 @@ Localize all strings into the following locale files: ca, de, en, es, fr, hi, id The VSCode extension has two main areas that require localization: -| Component | Path | Purpose | -|-----------|------|---------| -| **Core Extension** | `src/i18n/locales/` | Extension backend strings | -| **WebView UI** | `webview-ui/src/i18n/locales/` | User interface strings | +| Component | Path | Purpose | +| ------------------ | ------------------------------ | ------------------------- | +| **Core Extension** | `src/i18n/locales/` | Extension backend strings | +| **WebView UI** | `webview-ui/src/i18n/locales/` | User interface strings | ## Brand Voice, Tone, and Word Choice @@ -77,17 +77,19 @@ This guidance file is loaded at runtime and should be consulted for the latest b ### Trans Component Example Translation string: + ```json "changeSettings": "You can always change this at the bottom of the settings" ``` React component usage: + ```tsx - }} + i18nKey="welcome:telemetry.changeSettings" + components={{ + settingsLink: , + }} /> ``` @@ -105,19 +107,21 @@ React component usage: 1. First add or modify English strings, then ask for confirmation before translating to all other languages 2. Use this process for each localization task: - 1. Identify where the string appears in the UI/codebase - 2. Understand the context and purpose of the string - 3. Update English translation first - 4. Use the `search_files` tool to find JSON keys that are near new keys in English translations but do not yet exist in the other language files for `apply_diff` SEARCH context - 5. Create appropriate translations for all other supported languages utilizing the `search_files` result using `apply_diff` without reading every file - 6. Do not output the translated text into the chat, just modify the files - 7. Validate your changes with the missing translations script + + 1. Identify where the string appears in the UI/codebase + 2. Understand the context and purpose of the string + 3. Update English translation first + 4. Use the `search_files` tool to find JSON keys that are near new keys in English translations but do not yet exist in the other language files for `apply_diff` SEARCH context + 5. Create appropriate translations for all other supported languages utilizing the `search_files` result using `apply_diff` without reading every file + 6. Do not output the translated text into the chat, just modify the files + 7. Validate your changes with the missing translations script 3. Flag or comment if an English source string is incomplete ("please see this...") to avoid truncated or unclear translations 4. For UI elements, distinguish between: - - Button labels: Use short imperative commands ("Save", "Cancel") - - Tooltip text: Can be slightly more descriptive + + - Button labels: Use short imperative commands ("Save", "Cancel") + - Tooltip text: Can be slightly more descriptive 5. Preserve the original perspective: If text is a user command directed at the software, ensure the translation maintains this direction diff --git a/.roomodes b/.roomodes index ba17940035a..d166708c7af 100644 --- a/.roomodes +++ b/.roomodes @@ -146,3 +146,37 @@ customModes: - command - mcp source: project + - slug: deepseek-code + name: DeepSeek Code + roleDefinition: |- + You are Roo, an expert software engineer optimized for tool-driven workflows using DeepSeek models. + + You strictly use tools to inspect, analyze, and modify code. You work step-by-step, prioritizing workspace inspection before reasoning. You avoid long explanations and instead take concrete actions using available tools. + + You focus on precise coding assistance, repository understanding, debugging, and safe code modifications. + whenToUse: Use this mode when working with DeepSeek models for coding, debugging, repository exploration, and file modifications requiring strict tool usage. + description: DeepSeek-optimized coding assistant + groups: + - read + - edit + - command + - mcp + source: project + customInstructions: | + TOOL EXECUTION RULES (CRITICAL): + + Always use Roo tools when interacting with the workspace. + + After EVERY tool call, you MUST provide a short confirmation message describing the result before continuing. + + Workflow: + 1. Call ONE tool at a time. + 2. Wait for the result. + 3. Briefly summarize the result. + 4. Then decide the next action. + + Never call multiple tools in one response. + Never end a response immediately after a tool call. + Always include a short natural-language confirmation after tool usage. + + Prefer small sequential actions over complex plans. diff --git a/ARCHITECTURE_NOTES.md b/ARCHITECTURE_NOTES.md new file mode 100644 index 00000000000..58b5c75f3d1 --- /dev/null +++ b/ARCHITECTURE_NOTES.md @@ -0,0 +1,76 @@ +# ARCHITECTURE REPORT: The Governed AI-Native IDE + +**Role:** Forward Deployed Engineer (FDE) +**Framework:** TRACE (Trusted Runtime for Autonomous Containment and Evidence) + +--- + +## Executive Summary + +This report formalizes the architecture for a governed AI-Native IDE, engineered to bridge the Provenance Gap between probabilistic reasoning and deterministic software engineering (Entire, 2026). By embedding infrastructure-level mediation into the IDE tool loop, we replace "vibe coding" with cryptographic verification and structured intent (TRACE, 2026; Bora, 2024). + +--- + +## 1. How the VS Code Extension Works: Dual-Process Topology + +To ensure security and performance, the extension operates as a distributed system within VS Code (VS Code, 2026): + +### Extension Host (Logic Layer) + +A Node.js process where the core orchestrator (`src/core/Cline.ts`) manages the agentic loop. It has full privileges for filesystem access and terminal execution (VS Code, 2026). + +### Webview (UI Layer) + +A restricted React sandbox for the user interface. It communicates with the Host via the `postMessage` API, ensuring reasoning-heavy tasks do not block the UI thread (Ansible, 2026). + +> My architecture intercepts the Thinking-Acting-Observing loop at the Extension Host level, mediating every system-level tool call (e.g., `write_to_file`) before execution (Roo Code, 2026). + +--- + +## 2. Code & Design Architecture: The Shared Brain + +Based on my Phase 0 archaeological dig into the Roo Code "nervous system," I have implemented two critical intervention points (Bockeler, 2025): + +- **The Prompt Factory (`src/core/prompts/system.ts`)** + Modified the prompt builder to move from "Instruction-based" to "Context-based" engineering. The agent is now architecturally barred from code synthesis until it completes a mandatory "Reasoning Handshake" (Bora, 2024; Bockeler, 2025). + +- **The Shared Brain (`AGENT.md`)** + Acts as a persistent project "Constitution." It records lessons learned from failed verification loops, preventing Context Rot during parallel agent sessions (LF Projects, 2025). + +--- + +## 3. Architectural Decisions: The TRACE Hook Engine + +I have implemented the TRACE framework to derive assurance from infrastructure mediation rather than model behavior (TRACE, 2026). + +- **Command Classification:** Every tool is classified as Safe (Read/Search) or Destructive (Write/Execute) (Roo Code, 2026). +- **The Handshake (Pre-Hook):** Mutation is prohibited until the agent calls `select_active_intent(intent_id)`. This pauses the promise chain and injects `What-Boundaries-Success` (WBS) constraints from `.orchestration/active_intents.yaml` into the current context (Bora, 2024). +- **Autonomous Recovery:** If the engine blocks an action, it returns a standardized JSON error to the LLM, allowing the "silicon worker" to self-correct without human intervention (TRACE, 2026). + +--- + +## 4. Diagrams & Schemas + +### Advanced Intent-Code Traceability Flow + +I integrated Nancy Leveson’s Seven Levels of Intent Specification to provide a vertical trace from Level 1 (System Purpose) to Level 5 (Physical Code) (Navarro et al., 2001). + +### Code Snippet (Sequence Diagram) + +```mermaid +sequenceDiagram +participant LLM as AI Agent (Builder) +participant Hook as TRACE Hook Engine +participant AST as Tree-sitter Parser +participant FS as .orchestration/ (Ledger) + +LLM->>Hook: select_active_intent(INT-001) +Note right of Hook: Loads Level 3 WBS Constraints +Hook-->>LLM: Injected XML Constraints +LLM->>Hook: write_file(src/auth.ts, content) +Hook->>AST: Parse Block to AST Node +AST-->>Hook: Structural Identity +Hook->>Hook: Calculate H = SHA-256(Normalize(Block)) +Hook->>FS: Append Trace to agent_trace.jsonl +Hook-->>LLM: Success (Level 6 Operations Data) +``` diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000000..4a1679ed2d7 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ + +## [PHASE 4] Lesson Learned: Concurrency & Stale States +- **Incident:** STALE_FILE_CONFLICT detected. +- **Verification:** System successfully blocked a write where Disk Hash != Memory Hash. +- **Protocol Update:** Agents must perform a 'fresh read' before any destructive tool call to ensure the Semantic Ledger remains accurate. diff --git a/README.md b/README.md index 75f37762f93..5f6469237a3 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ - [简体中文](locales/zh-CN/README.md) - [繁體中文](locales/zh-TW/README.md) - ... - + --- @@ -66,10 +66,10 @@ Learn more: [Using Modes](https://docs.roocode.com/basic-usage/using-modes) •
-| | | | -| :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -|
Installing Roo Code |
Configuring Profiles |
Codebase Indexing | -|
Custom Modes |
Checkpoints |
Context Management | +| | | | +| :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +|
Installing Roo Code |
Configuring Profiles |
Codebase Indexing | +|
Custom Modes |
Checkpoints |
Context Management |

diff --git a/apps/web-roo-code/next-sitemap.config.cjs b/apps/web-roo-code/next-sitemap.config.cjs index e2b1e47e2c5..4242afdc6e9 100644 --- a/apps/web-roo-code/next-sitemap.config.cjs +++ b/apps/web-roo-code/next-sitemap.config.cjs @@ -1,159 +1,152 @@ -const path = require('path'); -const fs = require('fs'); -const matter = require('gray-matter'); +const path = require("path") +const fs = require("fs") +const matter = require("gray-matter") /** * Get published blog posts for sitemap * Note: This runs at build time, so recently-scheduled posts may lag */ function getPublishedBlogPosts() { - const BLOG_DIR = path.join(process.cwd(), 'src/content/blog'); - - if (!fs.existsSync(BLOG_DIR)) { - return []; - } - - const files = fs.readdirSync(BLOG_DIR).filter(f => f.endsWith('.md')); - const posts = []; - - // Get current time in PT for publish check - const formatter = new Intl.DateTimeFormat('en-US', { - timeZone: 'America/Los_Angeles', - year: 'numeric', - month: '2-digit', - day: '2-digit', - hour: '2-digit', - minute: '2-digit', - hour12: false, - }); - - const parts = formatter.formatToParts(new Date()); - const get = (type) => parts.find(p => p.type === type)?.value ?? ''; - const nowDate = `${get('year')}-${get('month')}-${get('day')}`; - const nowMinutes = parseInt(get('hour')) * 60 + parseInt(get('minute')); - - for (const file of files) { - const filepath = path.join(BLOG_DIR, file); - const raw = fs.readFileSync(filepath, 'utf8'); - const { data } = matter(raw); - - // Check if post is published - if (data.status !== 'published') continue; - - // Parse publish time - const timeMatch = data.publish_time_pt?.match(/^(1[0-2]|[1-9]):([0-5][0-9])(am|pm)$/i); - if (!timeMatch) continue; - - let hours = parseInt(timeMatch[1]); - const mins = parseInt(timeMatch[2]); - const isPm = timeMatch[3].toLowerCase() === 'pm'; - if (hours === 12) hours = isPm ? 12 : 0; - else if (isPm) hours += 12; - const postMinutes = hours * 60 + mins; - - // Check if post is past publish date/time - const isPublished = nowDate > data.publish_date || - (nowDate === data.publish_date && nowMinutes >= postMinutes); - - if (isPublished && data.slug) { - posts.push(data.slug); - } - } - - return posts; + const BLOG_DIR = path.join(process.cwd(), "src/content/blog") + + if (!fs.existsSync(BLOG_DIR)) { + return [] + } + + const files = fs.readdirSync(BLOG_DIR).filter((f) => f.endsWith(".md")) + const posts = [] + + // Get current time in PT for publish check + const formatter = new Intl.DateTimeFormat("en-US", { + timeZone: "America/Los_Angeles", + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + hour12: false, + }) + + const parts = formatter.formatToParts(new Date()) + const get = (type) => parts.find((p) => p.type === type)?.value ?? "" + const nowDate = `${get("year")}-${get("month")}-${get("day")}` + const nowMinutes = parseInt(get("hour")) * 60 + parseInt(get("minute")) + + for (const file of files) { + const filepath = path.join(BLOG_DIR, file) + const raw = fs.readFileSync(filepath, "utf8") + const { data } = matter(raw) + + // Check if post is published + if (data.status !== "published") continue + + // Parse publish time + const timeMatch = data.publish_time_pt?.match(/^(1[0-2]|[1-9]):([0-5][0-9])(am|pm)$/i) + if (!timeMatch) continue + + let hours = parseInt(timeMatch[1]) + const mins = parseInt(timeMatch[2]) + const isPm = timeMatch[3].toLowerCase() === "pm" + if (hours === 12) hours = isPm ? 12 : 0 + else if (isPm) hours += 12 + const postMinutes = hours * 60 + mins + + // Check if post is past publish date/time + const isPublished = nowDate > data.publish_date || (nowDate === data.publish_date && nowMinutes >= postMinutes) + + if (isPublished && data.slug) { + posts.push(data.slug) + } + } + + return posts } /** @type {import('next-sitemap').IConfig} */ module.exports = { - siteUrl: process.env.NEXT_PUBLIC_SITE_URL || 'https://roocode.com', - generateRobotsTxt: true, - generateIndexSitemap: false, // We don't need index sitemap for a small site - changefreq: 'monthly', - priority: 0.7, - sitemapSize: 5000, - exclude: [ - '/api/*', - '/server-sitemap-index.xml', - '/404', - '/500', - '/_not-found', - ], - robotsTxtOptions: { - policies: [ - { - userAgent: '*', - allow: '/', - }, - ], - additionalSitemaps: [ - // Add any additional sitemaps here if needed in the future - ], - }, - // Custom transform function to set specific priorities and change frequencies - transform: async (config, path) => { - // Set custom priority for specific pages - let priority = config.priority; - let changefreq = config.changefreq; - - if (path === '/') { - priority = 1.0; - changefreq = 'yearly'; - } else if (path === '/enterprise' || path === '/evals') { - priority = 0.8; - changefreq = 'monthly'; - } else if (path === '/privacy' || path === '/terms') { - priority = 0.5; - changefreq = 'yearly'; - } else if (path === '/blog') { - priority = 0.8; - changefreq = 'weekly'; - } else if (path.startsWith('/blog/')) { - priority = 0.7; - changefreq = 'monthly'; - } - - return { - loc: path, - changefreq, - priority, - lastmod: config.autoLastmod ? new Date().toISOString() : undefined, - alternateRefs: config.alternateRefs ?? [], - }; - }, - additionalPaths: async (config) => { - const result = []; - - // Add the /evals page since it's a dynamic route - result.push({ - loc: '/evals', - changefreq: 'monthly', - priority: 0.8, - lastmod: new Date().toISOString(), - }); - - // Add /blog index - result.push({ - loc: '/blog', - changefreq: 'weekly', - priority: 0.8, - lastmod: new Date().toISOString(), - }); - - // Add published blog posts - try { - const slugs = getPublishedBlogPosts(); - for (const slug of slugs) { - result.push({ - loc: `/blog/${slug}`, - changefreq: 'monthly', - priority: 0.7, - lastmod: new Date().toISOString(), - }); - } - } catch (e) { - console.warn('Could not load blog posts for sitemap:', e.message); - } - - return result; - }, -}; + siteUrl: process.env.NEXT_PUBLIC_SITE_URL || "https://roocode.com", + generateRobotsTxt: true, + generateIndexSitemap: false, // We don't need index sitemap for a small site + changefreq: "monthly", + priority: 0.7, + sitemapSize: 5000, + exclude: ["/api/*", "/server-sitemap-index.xml", "/404", "/500", "/_not-found"], + robotsTxtOptions: { + policies: [ + { + userAgent: "*", + allow: "/", + }, + ], + additionalSitemaps: [ + // Add any additional sitemaps here if needed in the future + ], + }, + // Custom transform function to set specific priorities and change frequencies + transform: async (config, path) => { + // Set custom priority for specific pages + let priority = config.priority + let changefreq = config.changefreq + + if (path === "/") { + priority = 1.0 + changefreq = "yearly" + } else if (path === "/enterprise" || path === "/evals") { + priority = 0.8 + changefreq = "monthly" + } else if (path === "/privacy" || path === "/terms") { + priority = 0.5 + changefreq = "yearly" + } else if (path === "/blog") { + priority = 0.8 + changefreq = "weekly" + } else if (path.startsWith("/blog/")) { + priority = 0.7 + changefreq = "monthly" + } + + return { + loc: path, + changefreq, + priority, + lastmod: config.autoLastmod ? new Date().toISOString() : undefined, + alternateRefs: config.alternateRefs ?? [], + } + }, + additionalPaths: async (config) => { + const result = [] + + // Add the /evals page since it's a dynamic route + result.push({ + loc: "/evals", + changefreq: "monthly", + priority: 0.8, + lastmod: new Date().toISOString(), + }) + + // Add /blog index + result.push({ + loc: "/blog", + changefreq: "weekly", + priority: 0.8, + lastmod: new Date().toISOString(), + }) + + // Add published blog posts + try { + const slugs = getPublishedBlogPosts() + for (const slug of slugs) { + result.push({ + loc: `/blog/${slug}`, + changefreq: "monthly", + priority: 0.7, + lastmod: new Date().toISOString(), + }) + } + } catch (e) { + console.warn("Could not load blog posts for sitemap:", e.message) + } + + return result + }, +} diff --git a/apps/web-roo-code/postcss.config.cjs b/apps/web-roo-code/postcss.config.cjs index 33ad091d26d..1b69d43b0ef 100644 --- a/apps/web-roo-code/postcss.config.cjs +++ b/apps/web-roo-code/postcss.config.cjs @@ -1,6 +1,6 @@ module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, } diff --git a/apps/web-roo-code/src/app/extension/page.tsx b/apps/web-roo-code/src/app/extension/page.tsx index 56219a34519..4e89ba420c9 100644 --- a/apps/web-roo-code/src/app/extension/page.tsx +++ b/apps/web-roo-code/src/app/extension/page.tsx @@ -37,8 +37,8 @@ export default async function ExtensionPage() {

Specialized modes stay on task and ship great code.
- Fully model-agnostic so you can use the best (or most cost-effective) model for - each task. + Fully model-agnostic so you can use the best (or most cost-effective) model for each + task.

Stop chasing this week's hot new model or CLI tool and go deep with Roo Code. diff --git a/apps/web-roo-code/src/app/pricing/page.tsx b/apps/web-roo-code/src/app/pricing/page.tsx index a46b5c67cc5..6851b47b6a1 100644 --- a/apps/web-roo-code/src/app/pricing/page.tsx +++ b/apps/web-roo-code/src/app/pricing/page.tsx @@ -291,11 +291,7 @@ export default function PricingPage() {

  • To pay for Cloud Agents running time (${PRICE_CREDITS}/hour)
  • To pay for AI model inference costs ( - + varies by model ) diff --git a/ellipsis.yaml b/ellipsis.yaml index 1044b94fdc1..de5dca39496 100644 --- a/ellipsis.yaml +++ b/ellipsis.yaml @@ -1,22 +1,21 @@ version: 1.3 pr_review: - - # Modify confidence_threshold to show fewer/more comments. Increase this to show fewer, but higher quality comments. - # If there’s too much noise, we suggest 0.9. The default value is 0.7. - confidence_threshold: 0.7 - - # If quiet mode is enabled, Ellipsis will only leave reviews when it has comments, so “Looks good to me” reviews - # will be skipped. This can reduce clutter. - quiet: true - - # You can disable automatic code review using auto_review_enabled. This will override any global settings you - # have configured via the web UI. - auto_review_enabled: true + # Modify confidence_threshold to show fewer/more comments. Increase this to show fewer, but higher quality comments. + # If there’s too much noise, we suggest 0.9. The default value is 0.7. + confidence_threshold: 0.7 - # You can enable auto-review on draft PRs using auto_review_draft. This will override any global settings you - # have configured via the web UI. - auto_review_draft: false - - # You can allow Ellipsis to approve PRs using enable_approve_prs. Note: in common branch GitHub protection configurations, - # the Ellipsis approval will count towards the approval total and allow the PR to be merged when it otherwise may not be. - enable_approve_prs: false + # If quiet mode is enabled, Ellipsis will only leave reviews when it has comments, so “Looks good to me” reviews + # will be skipped. This can reduce clutter. + quiet: true + + # You can disable automatic code review using auto_review_enabled. This will override any global settings you + # have configured via the web UI. + auto_review_enabled: true + + # You can enable auto-review on draft PRs using auto_review_draft. This will override any global settings you + # have configured via the web UI. + auto_review_draft: false + + # You can allow Ellipsis to approve PRs using enable_approve_prs. Note: in common branch GitHub protection configurations, + # the Ellipsis approval will count towards the approval total and allow the PR to be merged when it otherwise may not be. + enable_approve_prs: false diff --git a/locales/ca/README.md b/locales/ca/README.md index 0c09d8c6611..05c5dc09b76 100644 --- a/locales/ca/README.md +++ b/locales/ca/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -69,7 +69,7 @@ Més informació: [Ús de Modes](https://docs.roocode.com/basic-usage/using-mode | | | | | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
    Instal·lant Roo Code |
    Configurant perfils |
    Indexació de la base de codi | -|
    Modes personalitzats |
    Punts de control |
    Gestió de Context | +|
    Modes personalitzats |
    Punts de control |
    Gestió de Context |

    diff --git a/locales/de/README.md b/locales/de/README.md index 526d601e70b..8ab42086d54 100644 --- a/locales/de/README.md +++ b/locales/de/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -69,7 +69,7 @@ Mehr erfahren: [Modi verwenden](https://docs.roocode.com/basic-usage/using-modes | | | | | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
    Roo Code installieren |
    Profile konfigurieren |
    Codebasis-Indizierung | -|
    Benutzerdefinierte Modi |
    Checkpoints |
    Kontextverwaltung | +|
    Benutzerdefinierte Modi |
    Checkpoints |
    Kontextverwaltung |

    diff --git a/locales/es/README.md b/locales/es/README.md index 9e378b7fd7c..e7e5aad467b 100644 --- a/locales/es/README.md +++ b/locales/es/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -69,7 +69,7 @@ Más info: [Usar Modos](https://docs.roocode.com/basic-usage/using-modes) • [M | | | | | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
    Instalando Roo Code |
    Configurando perfiles |
    Indexación de la base de código | -|
    Modos personalizados |
    Checkpoints |
    Gestión de Contexto | +|
    Modos personalizados |
    Checkpoints |
    Gestión de Contexto |

    diff --git a/locales/fr/README.md b/locales/fr/README.md index 5197e76f0e9..546b669f665 100644 --- a/locales/fr/README.md +++ b/locales/fr/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -69,7 +69,7 @@ En savoir plus : [Utiliser les Modes](https://docs.roocode.com/basic-usage/using | | | | | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
    Installer Roo Code |
    Configurer les profils |
    Indexation de la base de code | -|
    Modes personnalisés |
    Checkpoints |
    Gestion du Contexte | +|
    Modes personnalisés |
    Checkpoints |
    Gestion du Contexte |

    diff --git a/locales/hi/README.md b/locales/hi/README.md index 8d12b689944..f84e32fd66a 100644 --- a/locales/hi/README.md +++ b/locales/hi/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -69,7 +69,7 @@ | | | | | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
    रू कोड इंस्टॉल करना |
    प्रोफाइल कॉन्फ़िगर करना |
    कोडबेस इंडेक्सिंग | -|
    कस्टम मोड |
    चेकपॉइंट्स |
    संदर्भ प्रबंधन | +|
    कस्टम मोड |
    चेकपॉइंट्स |
    संदर्भ प्रबंधन |

    diff --git a/locales/id/README.md b/locales/id/README.md index 657b1ab750f..0d74501f8cb 100644 --- a/locales/id/README.md +++ b/locales/id/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -69,7 +69,7 @@ Pelajari lebih lanjut: [Menggunakan Mode](https://docs.roocode.com/basic-usage/u | | | | | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
    Menginstal Roo Code |
    Mengonfigurasi Profil |
    Pengindeksan Basis Kode | -|
    Mode Kustom |
    Pos Pemeriksaan |
    Manajemen Konteks | +|
    Mode Kustom |
    Pos Pemeriksaan |
    Manajemen Konteks |

    diff --git a/locales/it/README.md b/locales/it/README.md index 9bd5ce9e81d..8bc8692e8bb 100644 --- a/locales/it/README.md +++ b/locales/it/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -69,7 +69,7 @@ Scopri di più: [Usare le Modalità](https://docs.roocode.com/basic-usage/using- | | | | | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
    Installazione di Roo Code |
    Configurazione dei profili |
    Indicizzazione della codebase | -|
    Modalità personalizzate |
    Checkpoint |
    Gestione del Contesto | +|
    Modalità personalizzate |
    Checkpoint |
    Gestione del Contesto |

    diff --git a/locales/ja/README.md b/locales/ja/README.md index 3b7a7a6e6ef..2456c0cf418 100644 --- a/locales/ja/README.md +++ b/locales/ja/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -69,7 +69,7 @@ Roo Codeは、あなたの働き方に合わせるように適応します。 | | | | | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
    Roo Codeのインストール |
    プロファイルの設定 |
    コードベースのインデックス作成 | -|
    カスタムモード |
    チェックポイント |
    コンテキスト管理 | +|
    カスタムモード |
    チェックポイント |
    コンテキスト管理 |

    diff --git a/locales/ko/README.md b/locales/ko/README.md index a53a1b965f0..758c7eda953 100644 --- a/locales/ko/README.md +++ b/locales/ko/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -69,7 +69,7 @@ Roo Code는 당신의 작업 방식에 맞춰 적응합니다. | | | | | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
    Roo Code 설치하기 |
    프로필 구성하기 |
    코드베이스 인덱싱 | -|
    사용자 지정 모드 |
    체크포인트 |
    컨텍스트 관리 | +|
    사용자 지정 모드 |
    체크포인트 |
    컨텍스트 관리 |

    diff --git a/locales/nl/README.md b/locales/nl/README.md index fa5454b9c54..92172552b3c 100644 --- a/locales/nl/README.md +++ b/locales/nl/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/locales/pl/README.md b/locales/pl/README.md index b8553a08c74..c1d0fc395f2 100644 --- a/locales/pl/README.md +++ b/locales/pl/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -69,7 +69,7 @@ Więcej: [Korzystanie z trybów](https://docs.roocode.com/basic-usage/using-mode | | | | | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
    Instalacja Roo Code |
    Konfiguracja profili |
    Indeksowanie bazy kodu | -|
    Tryby niestandardowe |
    Punkty kontrolne |
    Zarządzanie Kontekstem | +|
    Tryby niestandardowe |
    Punkty kontrolne |
    Zarządzanie Kontekstem |

    diff --git a/locales/pt-BR/README.md b/locales/pt-BR/README.md index 3b128b0fd39..215fd01ad18 100644 --- a/locales/pt-BR/README.md +++ b/locales/pt-BR/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -69,7 +69,7 @@ Saiba mais: [Usar Modos](https://docs.roocode.com/basic-usage/using-modes) • [ | | | | | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
    Instalando o Roo Code |
    Configurando perfis |
    Indexação da base de código | -|
    Modos personalizados |
    Checkpoints |
    Gerenciamento de Contexto | +|
    Modos personalizados |
    Checkpoints |
    Gerenciamento de Contexto |

    diff --git a/locales/ru/README.md b/locales/ru/README.md index 9abf4ae5110..02f79658fcf 100644 --- a/locales/ru/README.md +++ b/locales/ru/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -69,7 +69,7 @@ Roo Code адаптируется к вашему стилю работы, а н | | | | | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
    Установка Roo Code |
    Настройка профилей |
    Индексация кодовой базы | -|
    Пользовательские режимы |
    Контрольные точки |
    Управление Контекстом | +|
    Пользовательские режимы |
    Контрольные точки |
    Управление Контекстом |

    diff --git a/locales/tr/README.md b/locales/tr/README.md index ac5a7884070..df15ac0eb19 100644 --- a/locales/tr/README.md +++ b/locales/tr/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -66,10 +66,10 @@ Daha fazla: [Modları kullanma](https://docs.roocode.com/basic-usage/using-modes

    -| | | | -| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -|
    Roo Code Kurulumu |
    Profilleri Yapılandırma |
    Kod Tabanı İndeksleme | -|
    Özel Modlar |
    Kontrol Noktaları |
    Bağlam Yönetimi | +| | | | +| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +|
    Roo Code Kurulumu |
    Profilleri Yapılandırma |
    Kod Tabanı İndeksleme | +|
    Özel Modlar |
    Kontrol Noktaları |
    Bağlam Yönetimi |

    diff --git a/locales/vi/README.md b/locales/vi/README.md index bedaa3c26ac..d46dc802985 100644 --- a/locales/vi/README.md +++ b/locales/vi/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -66,10 +66,10 @@ Xem thêm: [Sử dụng Chế độ](https://docs.roocode.com/basic-usage/using-

    -| | | | -| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -|
    Cài đặt Roo Code |
    Định cấu hình Hồ sơ |
    Lập chỉ mục cơ sở mã | -|
    Chế độ tùy chỉnh |
    Điểm kiểm tra |
    Quản lý Ngữ cảnh | +| | | | +| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +|
    Cài đặt Roo Code |
    Định cấu hình Hồ sơ |
    Lập chỉ mục cơ sở mã | +|
    Chế độ tùy chỉnh |
    Điểm kiểm tra |
    Quản lý Ngữ cảnh |

    diff --git a/locales/zh-CN/README.md b/locales/zh-CN/README.md index a21e147f963..6a0e8868db6 100644 --- a/locales/zh-CN/README.md +++ b/locales/zh-CN/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -66,9 +66,9 @@ Roo Code 适应您的工作方式,而不是相反:

    -| | | | -| :-----------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------: | -|
    安装 Roo Code |
    配置个人资料 |
    代码库索引 | +| | | | +| :-----------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------: | +|
    安装 Roo Code |
    配置个人资料 |
    代码库索引 | |
    自定义模式 |
    检查点 |
    上下文管理 |
    diff --git a/locales/zh-TW/README.md b/locales/zh-TW/README.md index fe985d7ec89..719ba9bf5a2 100644 --- a/locales/zh-TW/README.md +++ b/locales/zh-TW/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/package.json b/package.json index de8dff751cb..8a135ffb8fd 100644 --- a/package.json +++ b/package.json @@ -1,74 +1,140 @@ { - "name": "roo-code", - "packageManager": "pnpm@10.8.1", - "engines": { - "node": "20.19.2" - }, - "scripts": { - "preinstall": "node scripts/bootstrap.mjs", - "prepare": "husky", - "install": "node scripts/bootstrap.mjs", - "install:all": "node scripts/bootstrap.mjs", - "lint": "turbo lint --log-order grouped --output-logs new-only", - "check-types": "turbo check-types --log-order grouped --output-logs new-only", - "test": "turbo test --log-order grouped --output-logs new-only", - "format": "turbo format --log-order grouped --output-logs new-only", - "build": "turbo build --log-order grouped --output-logs new-only", - "bundle": "turbo bundle --log-order grouped --output-logs new-only", - "bundle:nightly": "turbo bundle:nightly --log-order grouped --output-logs new-only", - "vsix": "turbo vsix --log-order grouped --output-logs new-only", - "vsix:nightly": "turbo vsix:nightly --log-order grouped --output-logs new-only", - "clean": "turbo clean --log-order grouped --output-logs new-only && rimraf dist out bin .vite-port .turbo", - "install:vsix": "pnpm install --frozen-lockfile && pnpm clean && pnpm vsix && node scripts/install-vsix.js", - "install:vsix:nightly": "pnpm install --frozen-lockfile && pnpm clean && pnpm vsix:nightly && node scripts/install-vsix.js --nightly", - "code-server:install": "node scripts/code-server.js", - "changeset:version": "cp CHANGELOG.md src/CHANGELOG.md && changeset version && cp -vf src/CHANGELOG.md .", - "knip": "knip --include files", - "evals": "dotenvx run -f packages/evals/.env.development packages/evals/.env.local -- docker compose -f packages/evals/docker-compose.yml --profile server --profile runner up --build --scale runner=0", - "npm:publish:types": "pnpm --filter @roo-code/types npm:publish" - }, - "devDependencies": { - "@changesets/cli": "^2.27.10", - "@dotenvx/dotenvx": "^1.34.0", - "@roo-code/config-typescript": "workspace:^", - "@types/glob": "^9.0.0", - "@types/node": "^24.1.0", - "@vscode/vsce": "3.3.2", - "esbuild": "^0.25.0", - "eslint": "^9.27.0", - "glob": "^11.1.0", - "husky": "^9.1.7", - "knip": "^5.44.4", - "lint-staged": "^16.0.0", - "mkdirp": "^3.0.1", - "only-allow": "^1.2.1", - "ovsx": "0.10.4", - "prettier": "^3.4.2", - "rimraf": "^6.0.1", - "tsx": "^4.19.3", - "turbo": "^2.5.6", - "typescript": "5.8.3" - }, - "lint-staged": { - "*.{js,jsx,ts,tsx,json,css,md}": [ - "prettier --write" - ] - }, - "pnpm": { - "onlyBuiltDependencies": [ - "@vscode/ripgrep" - ], - "overrides": { - "tar-fs": ">=3.1.1", - "esbuild": ">=0.25.0", - "undici": ">=5.29.0", - "brace-expansion": "^2.0.2", - "form-data": ">=4.0.4", - "bluebird": ">=3.7.2", - "glob": ">=11.1.0", - "@types/react": "^18.3.23", - "@types/react-dom": "^18.3.5", - "zod": "3.25.76" - } - } -} + "name": "roo-code", + "displayName": "Roo Code", + "description": "An AI-native IDE extension that can use your CLI and editor", + "version": "3.3.2", + "icon": "assets/icons/robot.svg", + "galleryBanner": { + "color": "#1e1e1e", + "theme": "dark" + }, + "publisher": "RooCode", + "repository": { + "type": "git", + "url": "https://github.com/Roo-Code/Roo-Code" + }, + "categories": [ + "AI", + "Programming Languages", + "Education", + "Assistant" + ], + "keywords": [ + "ai", + "llm", + "agentic", + "coding assistant", + "anthropic", + "claude", + "openai", + "gemini", + "ollama" + ], + "activationEvents": [ + "onView:roo-code.SidebarProvider" + ], + "main": "./dist/extension.js", + "browser": "./dist/extension.js", + "bin": { + "roo": "./bin/roo.js" + }, + "engines": { + "vscode": "^1.84.0" + }, + "contributes": { + "viewsContainers": { + "activitybar": [ + { + "id": "roo-code-SidebarContainer", + "icon": "assets/icons/robot.svg", + "title": "Roo Code" + } + ] + }, + "views": { + "roo-code-SidebarContainer": [ + { + "type": "webview", + "id": "roo-code.SidebarProvider", + "name": "" + } + ] + }, + "commands": [ + { + "command": "roo-code.plusButtonClicked", + "title": "New Task", + "icon": "$(add)" + }, + { + "command": "roo-code.mcpButtonClicked", + "title": "MCP Servers", + "icon": "$(server-process)" + }, + { + "command": "roo-code.historyButtonClicked", + "title": "History", + "icon": "$(history)" + }, + { + "command": "roo-code.settingsButtonClicked", + "title": "Settings", + "icon": "$(settings-gear)" + }, + { + "command": "roo-code.openInNewTab", + "title": "Open In New Tab" + } + ], + "menus": { + "view/title": [ + { + "command": "roo-code.plusButtonClicked", + "group": "navigation@1", + "when": "view == roo-code.SidebarProvider" + }, + { + "command": "roo-code.mcpButtonClicked", + "group": "navigation@2", + "when": "view == roo-code.SidebarProvider" + }, + { + "command": "roo-code.historyButtonClicked", + "group": "navigation@3", + "when": "view == roo-code.SidebarProvider" + }, + { + "command": "roo-code.settingsButtonClicked", + "group": "navigation@4", + "when": "view == roo-code.SidebarProvider" + } + ], + "commandPalette": [ + { + "command": "roo-code.openInNewTab", + "when": "true" + } + ] + }, + "configuration": { + "title": "Roo Code", + "properties": { + "roo-code.instructions": { + "type": "string", + "default": "", + "description": "Custom instructions to add to the end of every system prompt.", + "editPresentation": "multilineText" + } + } + } + }, + "scripts": { + "vscode:prepublish": "npm run package", + "compile": "node esbuild.js", + "bundle": "node esbuild.js", + "package": "node esbuild.js --production", + "watch": "node esbuild.js --watch", + "check-types": "tsc --noEmit", + "lint": "eslint src --ext ts" + } +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b461926f5e..50066f047ef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,6 +32,9 @@ importers: '@types/glob': specifier: ^9.0.0 version: 9.0.0 + '@types/js-yaml': + specifier: ^4.0.9 + version: 4.0.9 '@types/node': specifier: ^24.1.0 version: 24.2.1 @@ -4516,6 +4519,9 @@ packages: '@types/js-cookie@2.2.7': resolution: {integrity: sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==} + '@types/js-yaml@4.0.9': + resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -6927,6 +6933,7 @@ packages: glob@11.1.0: resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} engines: {node: 20 || >=22} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true global-agent@3.0.0: @@ -10101,7 +10108,7 @@ packages: tar@7.4.3: resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} engines: {node: '>=18'} - deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exhorbitant rates) by contacting i@izs.me + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} @@ -14733,6 +14740,8 @@ snapshots: '@types/js-cookie@2.2.7': {} + '@types/js-yaml@4.0.9': {} + '@types/json-schema@7.0.15': {} '@types/katex@0.16.7': {} @@ -15073,7 +15082,7 @@ snapshots: sirv: 3.0.1 tinyglobby: 0.2.14 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.2.1)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@20.17.57)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) '@vitest/utils@3.2.4': dependencies: diff --git a/src/core/tools/__tests__/useMcpToolTool.spec.ts b/src/core/tools/__tests__/useMcpToolTool.spec.ts index 27a991456ae..5ee826774f4 100644 --- a/src/core/tools/__tests__/useMcpToolTool.spec.ts +++ b/src/core/tools/__tests__/useMcpToolTool.spec.ts @@ -676,14 +676,12 @@ describe("useMcpToolTool", () => { mockProviderRef.deref.mockReturnValue({ getMcpHub: () => ({ callTool: vi.fn().mockResolvedValue(mockToolResult), - getAllServers: vi - .fn() - .mockReturnValue([ - { - name: "figma-server", - tools: [{ name: "get_screenshot", description: "Get screenshot" }], - }, - ]), + getAllServers: vi.fn().mockReturnValue([ + { + name: "figma-server", + tools: [{ name: "get_screenshot", description: "Get screenshot" }], + }, + ]), }), postMessageToWebview: vi.fn(), }) @@ -790,14 +788,12 @@ describe("useMcpToolTool", () => { mockProviderRef.deref.mockReturnValue({ getMcpHub: () => ({ callTool: vi.fn().mockResolvedValue(mockToolResult), - getAllServers: vi - .fn() - .mockReturnValue([ - { - name: "figma-server", - tools: [{ name: "get_screenshot", description: "Get screenshot" }], - }, - ]), + getAllServers: vi.fn().mockReturnValue([ + { + name: "figma-server", + tools: [{ name: "get_screenshot", description: "Get screenshot" }], + }, + ]), }), postMessageToWebview: vi.fn(), }) @@ -852,14 +848,12 @@ describe("useMcpToolTool", () => { mockProviderRef.deref.mockReturnValue({ getMcpHub: () => ({ callTool: vi.fn().mockResolvedValue(mockToolResult), - getAllServers: vi - .fn() - .mockReturnValue([ - { - name: "figma-server", - tools: [{ name: "get_screenshots", description: "Get screenshots" }], - }, - ]), + getAllServers: vi.fn().mockReturnValue([ + { + name: "figma-server", + tools: [{ name: "get_screenshots", description: "Get screenshots" }], + }, + ]), }), postMessageToWebview: vi.fn(), }) diff --git a/src/core/tools/select_active_intent.ts b/src/core/tools/select_active_intent.ts new file mode 100644 index 00000000000..ce95fd712dd --- /dev/null +++ b/src/core/tools/select_active_intent.ts @@ -0,0 +1,30 @@ +import * as fs from 'fs'; +import * as yaml from 'js-yaml'; // You may need to npm install js-yaml +import * as path from 'path'; + +export async function selectActiveIntent(intentId: string, workspaceRoot: string) { + const configPath = path.join(workspaceRoot, '.orchestration', 'active_intents.yaml'); + + // 1. Read the Intent File + const fileContents = fs.readFileSync(configPath, 'utf8'); + const data = yaml.load(fileContents) as any; + + // 2. Find the specific Intent + const intent = data.active_intents.find((i: any) => i.id === intentId); + + if (!intent) { + throw new Error(`Intent ID ${intentId} not found in .orchestration/active_intents.yaml`); + } + + // 3. Return the XML Context (This is what the AI sees) + return ` + + ${intent.id} + ${intent.name} + ${intent.owned_scope.join(', ')} + + ${intent.constraints.map((c: string) => `- ${c}`).join('\n ')} + + + `; +} \ No newline at end of file diff --git a/src/hooks/HookEngine.ts b/src/hooks/HookEngine.ts new file mode 100644 index 00000000000..1ca1a47f780 --- /dev/null +++ b/src/hooks/HookEngine.ts @@ -0,0 +1,38 @@ +import { IntentManager } from "./IntentManager" +import { TraceLogger } from "./TraceLogger" + +export class HookEngine { + private intentManager = new IntentManager() + private traceLogger = new TraceLogger() + + /** + * Intercepts the Thinking-Acting loop at the Extension Host level (VS Code, 2026). + */ + async preToolUse(toolName: string, args: any): Promise { + // Classification: Mediation depends on the risk level of the tool (TRACE, 2026) + const isDestructive = ["write_to_file", "execute_command", "apply_diff"].includes(toolName) + + if (toolName === "select_active_intent") { + return await this.intentManager.loadIntentContext(args.intent_id) + } + + // Enforcement: Fail-Closed halting if no intent is active (TRACE, 2026) + if (isDestructive && !this.intentManager.getActiveIntent()) { + throw new Error( + `Governance Violation: Mutation tool '${toolName}' blocked. You must call 'select_active_intent' first.`, + ) + } + + if (toolName === "write_to_file") { + this.intentManager.verifyScope(args.path) + } + } + + async postToolUse(toolName: string, args: any, result: string): Promise { + const activeIntentId = this.intentManager.getActiveIntent() + + if (toolName === "write_to_file" && activeIntentId) { + await this.traceLogger.logMutation(activeIntentId, args.path, args.content) + } + } +} diff --git a/src/hooks/IntentManager.ts b/src/hooks/IntentManager.ts new file mode 100644 index 00000000000..99a5c1bd36a --- /dev/null +++ b/src/hooks/IntentManager.ts @@ -0,0 +1,75 @@ +import * as fs from "fs/promises" +import * as path from "path" +import * as yaml from "js-yaml" +import { WBSContext } from "./types" + +export class IntentManager { + private activeIntent: WBSContext | null = null + private orchestrationPath = path.join(process.cwd(), ".orchestration", "active_intents.yaml") + + async loadIntentContext(intentId: string): Promise { + try { + const fileContent = await fs.readFile(this.orchestrationPath, "utf8") + const data: any = yaml.load(fileContent) + + if (!data?.active_intents) { + throw new Error("No active_intents section found in YAML") + } + + const intent = data.active_intents.find((i: any) => i.id === intentId) + + if (!intent) { + throw new Error(`Intent ID ${intentId} not found in .orchestration/active_intents.yaml`) + } + + // Ensure all arrays are properly typed + const what: string[] = Array.isArray(intent.what) ? intent.what : [String(intent.what)] + const constraints: string[] = Array.isArray(intent.constraints) + ? intent.constraints + : [String(intent.constraints)] + const acceptance_criteria: string[] = Array.isArray(intent.acceptance_criteria) + ? intent.acceptance_criteria + : [String(intent.acceptance_criteria)] + const owned_scope: string[] = Array.isArray(intent.owned_scope) + ? intent.owned_scope + : [String(intent.owned_scope)] + + // Map to full WBSContext type + this.activeIntent = { + id: intent.id, + what, + constraints, + acceptance_criteria, + owned_scope, + boundaries: constraints, + success: acceptance_criteria, + } as WBSContext + + return ` +ID: ${intent.id} +WHAT: ${what.join(", ")} +BOUNDARIES: ${constraints.join(", ")} +SUCCESS: ${acceptance_criteria.join(", ")} +OWNED_SCOPE: ${owned_scope.join(", ")} +` + } catch (error: any) { + throw new Error(`Intent Handshake Failed: ${error.message}`) + } + } + + getActiveIntent(): string | null { + return this.activeIntent?.id || null + } + + verifyScope(targetPath: string): void { + if (!this.activeIntent) return + + const ownedScope: string[] = this.activeIntent.owned_scope ?? [] + + const isAuthorized = ownedScope.some((pattern: string) => targetPath.includes(pattern.replace("/**", ""))) + + if (!isAuthorized) { + throw new Error(`Scope Violation: Intent ${this.activeIntent.id} is not authorized to edit ${targetPath}`) + } + } +} diff --git a/src/hooks/TraceLogger.ts b/src/hooks/TraceLogger.ts new file mode 100644 index 00000000000..24371b66bc6 --- /dev/null +++ b/src/hooks/TraceLogger.ts @@ -0,0 +1,47 @@ +import * as crypto from "crypto" +import * as fs from "fs/promises" +import * as path from "path" +import { TraceRecord } from "./types" + +export class TraceLogger { + private ledgerPath = path.join(process.cwd(), ".orchestration", "agent_trace.jsonl") + + /** + * Calculates the content hash H = SHA-256(Normalize(Block)) + * to provide Structural Identity (Dropstone, 2025). + */ + private calculateSpatialHash(content: string): string { + const normalized = content.replace(/\s+/g, " ").trim() // Normalize whitespace + return crypto.createHash("sha256").update(normalized).digest("hex") + } + + async logMutation(intentId: string, filePath: string, content: string): Promise { + const hash = this.calculateSpatialHash(content) + + const record: TraceRecord = { + version: "1.0", + id: crypto.randomUUID(), + timestamp: new Date().toISOString(), + files: [ + { + path: filePath, + conversations: [ + { + contributor: { type: "ai" }, + ranges: [ + { + start_line: 1, // Full file write context + end_line: content.split("\n").length, + content_hash: `sha256:${hash}`, + }, + ], + }, + ], + }, + ], + } + + // Append to the hash-chained evidence log (TRACE, 2026) + await fs.appendFile(this.ledgerPath, JSON.stringify(record) + "\n") + } +} diff --git a/src/hooks/types.ts b/src/hooks/types.ts new file mode 100644 index 00000000000..c0e1737e5ed --- /dev/null +++ b/src/hooks/types.ts @@ -0,0 +1,48 @@ +/** + * MutationClass differentiates between changes that preserve existing + * business logic (Refactor) and those that introduce new requirements (Evolution). + */ +export enum MutationClass { + AST_REFACTOR = "AST_REFACTOR", + INTENT_EVOLUTION = "INTENT_EVOLUTION", +} + +/** + * WBSContext formalizes the "What-Boundaries-Success" framework + * to reduce the LLM's solution space through structured constraints. + */ +export interface WBSContext { + id: string // e.g., "INT-001" + owned_scope: string[] // Glob patterns of authorized files + what: string[] // Functional requirements + boundaries: string[] // "Soft constraints" to prevent hallucinations + success: string[] // Measurable criteria for "Definition of Done" +} + +/** + * TraceRecord follows the Agent Trace specification to provide + * a position-independent audit log of AI contributions. + */ +export interface TraceRecord { + version: string + id: string + timestamp: string + vcs?: { + type: "git" | "jj" | "hg" | "svn" + revision: string + } + files: Array<{ + path: string + conversations: Array<{ + contributor: { + type: "human" | "ai" | "mixed" | "unknown" + model_id?: string + } + ranges: Array<{ + start_line: number + end_line: number + content_hash?: string + }> + }> + }> +} diff --git a/src/services/checkpoints/__tests__/ShadowCheckpointService.spec.ts b/src/services/checkpoints/__tests__/ShadowCheckpointService.spec.ts index f2d9d12dd07..92bf1f8e7df 100644 --- a/src/services/checkpoints/__tests__/ShadowCheckpointService.spec.ts +++ b/src/services/checkpoints/__tests__/ShadowCheckpointService.spec.ts @@ -942,9 +942,7 @@ describe("worktree path comparison", () => { // Second init with stubbed worktree returning a trailing newline const service2 = new RepoPerTaskCheckpointService("trim-test-2", shadowDir, workspaceDir, () => {}) - vitest - .spyOn(service2 as any, "getShadowGitConfigWorktree") - .mockResolvedValue(workspaceDir + "\n") + vitest.spyOn(service2 as any, "getShadowGitConfigWorktree").mockResolvedValue(workspaceDir + "\n") await service2.initShadowGit() } finally { @@ -983,9 +981,7 @@ describe("worktree path comparison", () => { // Second init should throw because core.worktree is missing const service2 = new RepoPerTaskCheckpointService("missing-test-2", shadowDir, workspaceDir, () => {}) - await expect(service2.initShadowGit()).rejects.toThrowError( - /core\.worktree to be set/, - ) + await expect(service2.initShadowGit()).rejects.toThrowError(/core\.worktree to be set/) } finally { vitest.restoreAllMocks() await fs.rm(shadowDir, { recursive: true, force: true }) diff --git a/webview-ui/.gitignore b/webview-ui/.gitignore index 1f81cba3f58..87a0ccda68e 100644 --- a/webview-ui/.gitignore +++ b/webview-ui/.gitignore @@ -1,27 +1,37 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp +# -------------------------------------------------- +# Dependencies +# -------------------------------------------------- +node_modules/ +.pnp/ .pnp.js -# testing -/coverage +# pnpm +pnpm-lock.yaml + +# -------------------------------------------------- +# Build Outputs +# -------------------------------------------------- +dist/ +build/ +out/ +.next/ +coverage/ +*.tsbuildinfo -# production -/build +# Webview / Vite +webview-ui/dist/ +webview-ui/.vite/ -# misc -.DS_Store +# -------------------------------------------------- +# Environment Files +# -------------------------------------------------- +.env .env.local .env.development.local .env.test.local .env.production.local -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -*storybook.log - -tsconfig.tsbuildinfo +# -------------------------------------------------- +# Logs +# -------------------------------------------------- +npm-debug.log diff --git a/webview-ui/src/components/marketplace/MarketplaceView.tsx b/webview-ui/src/components/marketplace/MarketplaceView.tsx index 94c50b80ab9..0ab5430eec1 100644 --- a/webview-ui/src/components/marketplace/MarketplaceView.tsx +++ b/webview-ui/src/components/marketplace/MarketplaceView.tsx @@ -108,7 +108,7 @@ export function MarketplaceView({ stateManager, onDone, targetTab }: Marketplace onClick={() => onDone?.()} aria-label={t("settings:back")}> - {t("settings:back")} + {t("settings:back")}

    {t("marketplace:title")}