mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-17 23:51:08 +00:00
Merge b26d8644ff into 96d6e43643
This commit is contained in:
commit
9b91fbbb00
45 changed files with 1911 additions and 1321 deletions
12
.clinerules
Normal file
12
.clinerules
Normal file
|
|
@ -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 <owned_scope> 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 '<INTENT_ID>' '<FILE_PATH>' '<NEW_CONTENT>'
|
||||
- This is mandatory for traceability.
|
||||
206
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
206
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
158
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
158
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
|
|
@ -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: 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: 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
|
||||
- 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: 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: 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: markdown
|
||||
attributes:
|
||||
value: |
|
||||
---
|
||||
Optional (for contributors): You can stop here if you're just proposing the improvement.
|
||||
- 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: 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: 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: proposed-solution
|
||||
attributes:
|
||||
label: Proposed approach (optional)
|
||||
description: If you have an idea, describe it briefly in plain language.
|
||||
- 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: risks
|
||||
attributes:
|
||||
label: Trade-offs / risks (optional)
|
||||
description: Potential downsides or alternatives considered.
|
||||
- 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: 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: risks
|
||||
attributes:
|
||||
label: Trade-offs / risks (optional)
|
||||
description: Potential downsides or alternatives considered.
|
||||
|
|
|
|||
104
.github/ISSUE_TEMPLATE/marketplace.yml
vendored
104
.github/ISSUE_TEMPLATE/marketplace.yml
vendored
|
|
@ -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
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Checklist
|
||||
options:
|
||||
- label: I've searched existing issues for duplicates
|
||||
required: true
|
||||
|
|
|
|||
98
.github/actions/slack-notify/action.yml
vendored
98
.github/actions/slack-notify/action.yml
vendored
|
|
@ -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<<EOF" >> $GITHUB_OUTPUT
|
||||
echo -e "$failed_list" | sed '/^$/d' >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
echo "failed_jobs<<EOF" >> $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 }}
|
||||
|
|
|
|||
0
.github/copilot-instructions.md
vendored
Normal file
0
.github/copilot-instructions.md
vendored
Normal file
8
.github/dependabot.yml
vendored
8
.github/dependabot.yml
vendored
|
|
@ -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"
|
||||
|
|
|
|||
232
.github/workflows/changeset-release.yml
vendored
232
.github/workflows/changeset-release.yml
vendored
|
|
@ -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 }}
|
||||
|
|
|
|||
682
.github/workflows/cli-release.yml
vendored
682
.github/workflows/cli-release.yml
vendored
|
|
@ -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
|
||||
# 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 }}
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
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: 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: 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 extension bundle
|
||||
run: pnpm bundle
|
||||
|
||||
- name: Build CLI
|
||||
run: pnpm --filter @roo-code/cli build
|
||||
- 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"
|
||||
- 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"
|
||||
# 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"
|
||||
# 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/"
|
||||
# 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"
|
||||
# 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/"
|
||||
# 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"
|
||||
# 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
|
||||
# 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"
|
||||
# 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"
|
||||
chmod +x "$RELEASE_DIR/bin/roo"
|
||||
|
||||
# Create empty .env file.
|
||||
touch "$RELEASE_DIR/.env"
|
||||
# Create empty .env file.
|
||||
touch "$RELEASE_DIR/.env"
|
||||
|
||||
# Create tarball.
|
||||
echo "Creating tarball..."
|
||||
tar -czvf "$TARBALL" "$RELEASE_DIR"
|
||||
# Create tarball.
|
||||
echo "Creating tarball..."
|
||||
tar -czvf "$TARBALL" "$RELEASE_DIR"
|
||||
|
||||
# Clean up release directory.
|
||||
rm -rf "$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
|
||||
# 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"
|
||||
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"
|
||||
- name: Verify tarball
|
||||
env:
|
||||
PLATFORM: ${{ matrix.platform }}
|
||||
run: |
|
||||
TARBALL="roo-cli-${PLATFORM}.tar.gz"
|
||||
|
||||
# Create temp directory for verification.
|
||||
VERIFY_DIR=$(mktemp -d)
|
||||
# Create temp directory for verification.
|
||||
VERIFY_DIR=$(mktemp -d)
|
||||
|
||||
# Extract and verify structure.
|
||||
tar -xzf "$TARBALL" -C "$VERIFY_DIR"
|
||||
# Extract and verify structure.
|
||||
tar -xzf "$TARBALL" -C "$VERIFY_DIR"
|
||||
|
||||
echo "Verifying tarball contents..."
|
||||
ls -la "$VERIFY_DIR/roo-cli-${PLATFORM}/"
|
||||
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; }
|
||||
# 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!"
|
||||
echo "Tarball verification passed!"
|
||||
|
||||
# Cleanup.
|
||||
rm -rf "$VERIFY_DIR"
|
||||
# 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
|
||||
- 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
|
||||
# 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
|
||||
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: 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: 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: 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"
|
||||
- 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 [ -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<<EOF" >> $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
|
||||
if [ -n "$CONTENT" ]; then
|
||||
echo "Found changelog content"
|
||||
echo "content<<EOF" >> $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<<EOF" >> $GITHUB_OUTPUT
|
||||
cat release/*.sha256 >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
- name: Generate checksums summary
|
||||
id: checksums
|
||||
run: |
|
||||
echo "checksums<<EOF" >> $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: 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: 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)
|
||||
- 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
|
||||
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"
|
||||
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/*
|
||||
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"
|
||||
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 }}
|
||||
# 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
|
||||
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
|
||||
- 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
|
||||
|
|
|
|||
138
.github/workflows/codeql.yml
vendored
138
.github/workflows/codeql.yml
vendored
|
|
@ -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}}"
|
||||
|
|
|
|||
160
.github/workflows/marketplace-publish.yml
vendored
160
.github/workflows/marketplace-publish.yml
vendored
|
|
@ -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}"
|
||||
|
|
|
|||
90
.github/workflows/nightly-publish.yml
vendored
90
.github/workflows/nightly-publish.yml
vendored
|
|
@ -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)"
|
||||
|
|
|
|||
108
.github/workflows/update-contributors.yml
vendored
108
.github/workflows/update-contributors.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
12
.github/workflows/website-deploy.yml
vendored
12
.github/workflows/website-deploy.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
14
.gitignore
vendored
14
.gitignore
vendored
|
|
@ -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
|
||||
10
.intentignore
Normal file
10
.intentignore
Normal file
|
|
@ -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/
|
||||
BIN
.nvmrc
BIN
.nvmrc
Binary file not shown.
15
.orchestration/active_intents.yaml
Normal file
15
.orchestration/active_intents.yaml
Normal file
|
|
@ -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"
|
||||
1
.orchestration/agent_trace.jsonl
Normal file
1
.orchestration/agent_trace.jsonl
Normal file
|
|
@ -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"}
|
||||
34
.orchestration/hooks/init_zvec.py
Normal file
34
.orchestration/hooks/init_zvec.py
Normal file
|
|
@ -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()
|
||||
43
.orchestration/hooks/tmd.py
Normal file
43
.orchestration/hooks/tmd.py
Normal file
|
|
@ -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 <intent_id> <file_path> <content>
|
||||
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 <intent_id> <file_path> <content>")
|
||||
0
.orchestration/intent_map.md
Normal file
0
.orchestration/intent_map.md
Normal file
1
.orchestration/phase2_check.txt
Normal file
1
.orchestration/phase2_check.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
Human edited this first!
|
||||
11
.orchestration/security_policy.json
Normal file
11
.orchestration/security_policy.json
Normal file
|
|
@ -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."
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
17
.roo/rules-deepseek-code/instructions.txt
Normal file
17
.roo/rules-deepseek-code/instructions.txt
Normal file
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <settingsLink>settings</settingsLink>"
|
||||
```
|
||||
|
||||
React component usage:
|
||||
|
||||
```tsx
|
||||
<Trans
|
||||
i18nKey="welcome:telemetry.changeSettings"
|
||||
components={{
|
||||
settingsLink: <VSCodeLink href="#" onClick={handleOpenSettings} />
|
||||
}}
|
||||
i18nKey="welcome:telemetry.changeSettings"
|
||||
components={{
|
||||
settingsLink: <VSCodeLink href="#" onClick={handleOpenSettings} />,
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
34
.roomodes
34
.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.
|
||||
|
|
|
|||
76
ARCHITECTURE_NOTES.md
Normal file
76
ARCHITECTURE_NOTES.md
Normal file
|
|
@ -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)
|
||||
```
|
||||
5
CLAUDE.md
Normal file
5
CLAUDE.md
Normal file
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ export default async function ExtensionPage() {
|
|||
<p className="mt-4 max-w-lg text-lg text-muted-foreground text-center md:text-left sm:mt-6">
|
||||
Specialized modes stay on task and ship great code.
|
||||
<br />
|
||||
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.
|
||||
</p>
|
||||
<p className="max-w-lg text-lg text-muted-foreground text-center md:text-left sm:mt-6">
|
||||
Stop chasing this week's hot new model or CLI tool and go deep with Roo Code.
|
||||
|
|
|
|||
|
|
@ -291,11 +291,7 @@ export default function PricingPage() {
|
|||
<li>To pay for Cloud Agents running time (${PRICE_CREDITS}/hour)</li>
|
||||
<li>
|
||||
To pay for AI model inference costs (
|
||||
<a
|
||||
href="/provider"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline">
|
||||
<a href="/provider" target="_blank" rel="noopener noreferrer" className="underline">
|
||||
varies by model
|
||||
</a>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
212
package.json
212
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"
|
||||
}
|
||||
}
|
||||
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
|
|
@ -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
|
||||
|
|
@ -4552,6 +4555,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==}
|
||||
|
||||
|
|
@ -14763,6 +14769,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': {}
|
||||
|
|
@ -15099,7 +15107,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:
|
||||
|
|
|
|||
30
src/core/tools/select_active_intent.ts
Normal file
30
src/core/tools/select_active_intent.ts
Normal file
|
|
@ -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_context>
|
||||
<id>${intent.id}</id>
|
||||
<name>${intent.name}</name>
|
||||
<owned_scope>${intent.owned_scope.join(', ')}</owned_scope>
|
||||
<constraints>
|
||||
${intent.constraints.map((c: string) => `- ${c}`).join('\n ')}
|
||||
</constraints>
|
||||
</intent_context>
|
||||
`;
|
||||
}
|
||||
38
src/hooks/HookEngine.ts
Normal file
38
src/hooks/HookEngine.ts
Normal file
|
|
@ -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<string | void> {
|
||||
// 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<void> {
|
||||
const activeIntentId = this.intentManager.getActiveIntent()
|
||||
|
||||
if (toolName === "write_to_file" && activeIntentId) {
|
||||
await this.traceLogger.logMutation(activeIntentId, args.path, args.content)
|
||||
}
|
||||
}
|
||||
}
|
||||
75
src/hooks/IntentManager.ts
Normal file
75
src/hooks/IntentManager.ts
Normal file
|
|
@ -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<string> {
|
||||
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 `<intent_context>
|
||||
ID: ${intent.id}
|
||||
WHAT: ${what.join(", ")}
|
||||
BOUNDARIES: ${constraints.join(", ")}
|
||||
SUCCESS: ${acceptance_criteria.join(", ")}
|
||||
OWNED_SCOPE: ${owned_scope.join(", ")}
|
||||
</intent_context>`
|
||||
} 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}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
47
src/hooks/TraceLogger.ts
Normal file
47
src/hooks/TraceLogger.ts
Normal file
|
|
@ -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<void> {
|
||||
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")
|
||||
}
|
||||
}
|
||||
48
src/hooks/types.ts
Normal file
48
src/hooks/types.ts
Normal file
|
|
@ -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
|
||||
}>
|
||||
}>
|
||||
}>
|
||||
}
|
||||
46
webview-ui/.gitignore
vendored
46
webview-ui/.gitignore
vendored
|
|
@ -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
|
||||
|
||||
# production
|
||||
/build
|
||||
# --------------------------------------------------
|
||||
# Build Outputs
|
||||
# --------------------------------------------------
|
||||
dist/
|
||||
build/
|
||||
out/
|
||||
.next/
|
||||
coverage/
|
||||
*.tsbuildinfo
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
# Webview / Vite
|
||||
webview-ui/dist/
|
||||
webview-ui/.vite/
|
||||
|
||||
# --------------------------------------------------
|
||||
# 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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue