Compare commits

...

19 Commits

Author SHA1 Message Date
inigo
d81efef324 cleanup
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-19 10:39:06 -07:00
GitHub Actions
c3a32e4ccf chore: Update CHANGELOG.md 2025-09-08 23:38:38 +00:00
GitHub Actions
2511feadf3 chore: Update CHANGELOG.md 2025-09-08 23:38:22 +00:00
bogini
bdba4a874d Merge pull request #7224 from anthropics/inigo/fix-repository-dispatch
Update workflow
2025-09-05 15:27:14 -07:00
inigo
cd043128fe Update workflow 2025-09-05 15:26:12 -07:00
inigo
8fba17cb99 Fix cross-repo workflow trigger mechanism 2025-09-05 15:15:25 -07:00
bogini
2b3a504f85 Merge pull request #7211 from anthropics/inigo/make-workflow-name-configurable
Add workflow configuration
2025-09-05 10:27:45 -07:00
inigo
1bcc5cf5bd msg 2025-09-05 09:21:33 -07:00
inigo
3e00a44590 Add workflow variable 2025-09-05 09:18:42 -07:00
bogini
702c601369 Merge pull request #7198 from anthropics/inigo/use-workflow-dispatch-for-issue-detective
Update workflow configuration
2025-09-05 00:17:13 -07:00
inigo
542b57b9a4 Update workflow trigger method 2025-09-05 00:16:39 -07:00
bogini
5c2a1e1d2e Merge pull request #7192 from anthropics/inigo/update-issue-notify-repository-dispatch
feat: update issue-notify to use repository_dispatch
2025-09-04 22:30:49 -07:00
inigo
156d9e9e3f feat: update issue-notify to use repository_dispatch
Switch from workflow_dispatch to repository_dispatch for cross-repo
triggering of issue-detective workflow in claude-cli-internal.

Changes:
- Use gh api with repository_dispatch endpoint
- Send issue_url in client_payload
- Support ISSUE_NOTIFY_TOKEN secret for better permissions
- Remove dependency on ISSUE_NOTIFY_WORKFLOW_NAME secret

This enables automatic issue detective analysis when issues are
opened in claude-code repository.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-04 22:24:51 -07:00
bogini
3404b075ec Merge pull request #7180 from anthropics/inigo/issue-templates
Update issue templates
2025-09-04 21:46:57 -07:00
GitHub Actions
72042e95fb chore: Update CHANGELOG.md 2025-09-05 00:56:17 +00:00
inigo
1feaffa747 Update issue templates
Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-04 17:00:14 -07:00
bogini
7127181c79 Merge pull request #7170 from anthropics/inigo/update-issue-notification-workflow
Update issue notification workflow
2025-09-04 14:31:58 -07:00
inigo
e66b150c0e Update issue notification workflow
- Simplify workflow to use built-in GitHub token
- Remove external dependencies
- Improve error handling and logging
2025-09-04 14:28:04 -07:00
Dalton Flanagan
dbff8bea24 Merge pull request #7101 from anthropics/dalton/readme-update-data-usage
Update README.md data usage section
2025-09-03 19:33:09 -07:00
14 changed files with 706 additions and 738 deletions

View File

@@ -1,34 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: '[BUG] '
labels: bug
assignees: ''
---
## Environment
- Platform (select one):
- [ ] Anthropic API
- [ ] AWS Bedrock
- [ ] Google Vertex AI
- [ ] Other: <!-- specify -->
- Claude CLI version: <!-- output of `claude --version` -->
- Operating System: <!-- e.g. macOS 14.3, Windows 11, Ubuntu 22.04 -->
- Terminal: <!-- e.g. iTerm2, Terminal App -->
## Bug Description
<!-- A clear and concise description of the bug -->
## Steps to Reproduce
1. <!-- First step -->
2. <!-- Second step -->
3. <!-- And so on... -->
## Expected Behavior
<!-- What you expected to happen -->
## Actual Behavior
<!-- What actually happened -->
## Additional Context
<!-- Add any other context about the problem here, such as screenshots, logs, etc. -->

188
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,188 @@
name: 🐛 Bug Report
description: Report a bug or unexpected behavior in Claude Code
title: "[BUG] "
labels:
- bug
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to report this bug! Please fill out the sections below to help us understand and fix the issue.
Before submitting, please check:
- You're using the [latest version](https://www.npmjs.com/package/@anthropic-ai/claude-code?activeTab=versions) of Claude Code (`claude --version`)
- This issue hasn't already been reported by searching [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug).
- This is a bug, not a feature request or support question
- type: checkboxes
id: preflight
attributes:
label: Preflight Checklist
description: Please confirm before submitting
options:
- label: I have searched [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug) and this hasn't been reported yet
required: true
- label: This is a single bug report (please file separate reports for different bugs)
required: true
- label: I am using the latest version of Claude Code
required: true
- type: textarea
id: actual
attributes:
label: What's Wrong?
description: Describe what's happening that shouldn't be
placeholder: |
When I try to create a Python file, Claude shows an error "EACCES: permission denied" and the file isn't created.
The command fails immediately after accepting the file write permission...
validations:
required: true
- type: textarea
id: expected
attributes:
label: What Should Happen?
description: Describe the expected behavior
placeholder: Claude should create a Python script file successfully without errors
validations:
required: true
- type: textarea
id: error_output
attributes:
label: Error Messages/Logs
description: If you see any error messages, paste them here
placeholder: |
Paste any error output, stack traces, or relevant logs here.
This will be automatically formatted as code.
render: shell
validations:
required: false
- type: textarea
id: reproduction
attributes:
label: Steps to Reproduce
description: |
Please provide clear, numbered steps that anyone can follow to reproduce the issue.
**Important**: Include any necessary code, file contents, or context needed to reproduce the bug.
If the issue involves specific files or code, please create a minimal example.
placeholder: |
1. Create a file `test.py` with this content:
```python
def hello():
print("test")
```
2. Run `claude "add type hints to test.py"`
3. When prompted for file access, accept
4. Error appears: "Unable to parse..."
Note: The bug only happens with Python files containing...
validations:
required: true
- type: dropdown
id: model
attributes:
label: Claude Model
description: Which model were you using? (Run `/model` to check)
options:
- Sonnet (default)
- Opus
- Not sure / Multiple models
- Other
validations:
required: false
- type: dropdown
id: regression
attributes:
label: Is this a regression?
description: Did this work in a previous version?
options:
- "Yes, this worked in a previous version"
- "No, this never worked"
- "I don't know"
validations:
required: true
- type: input
id: working_version
attributes:
label: Last Working Version
description: If this is a regression, which version last worked? This helps expedite a fix.
placeholder: "e.g., 1.0.100"
validations:
required: false
- type: input
id: version
attributes:
label: Claude Code Version
description: Run `claude --version` and paste the output
placeholder: "e.g., 1.0.123 (Claude Code)"
validations:
required: true
- type: dropdown
id: platform
attributes:
label: Platform
description: Which API platform are you using?
options:
- Anthropic API
- AWS Bedrock
- Google Vertex AI
- Other
validations:
required: true
- type: dropdown
id: os
attributes:
label: Operating System
options:
- macOS
- Windows
- Ubuntu/Debian Linux
- Other Linux
- Other
validations:
required: true
- type: dropdown
id: terminal
attributes:
label: Terminal/Shell
description: Which terminal are you using?
options:
- Terminal.app (macOS)
- Warp
- Cursor
- iTerm2
- IntelliJ IDEA terminal
- VS Code integrated terminal
- PyCharm terminal
- Windows Terminal
- PowerShell
- WSL (Windows Subsystem for Linux)
- Xterm
- Non-interactive/CI environment
- Other
validations:
required: true
- type: textarea
id: additional
attributes:
label: Additional Information
description: |
Anything else that might help us understand the issue?
- Screenshots (drag and drop images here)
- Configuration files
- Related files or code
- Links to repositories demonstrating the issue
placeholder: Any additional context, screenshots, or information...
validations:
required: false

17
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
blank_issues_enabled: false
contact_links:
- name: 💬 Discord Community
url: https://anthropic.com/discord
about: Get help, ask questions, and chat with other Claude Code users
- name: 📖 Documentation
url: https://docs.anthropic.com/en/docs/claude-code
about: Read the official documentation and guides
- name: 🎓 Getting Started Guide
url: https://docs.anthropic.com/en/docs/claude-code/getting-started
about: New to Claude Code? Start here
- name: 🔧 Troubleshooting Guide
url: https://docs.anthropic.com/en/docs/claude-code/troubleshooting
about: Common issues and how to fix them
- name: 💡 Discussions
url: https://github.com/anthropics/claude-code/discussions
about: Share ideas, tips, and chat with maintainers

117
.github/ISSUE_TEMPLATE/documentation.yml vendored Normal file
View File

@@ -0,0 +1,117 @@
name: 📚 Documentation Issue
description: Report missing, unclear, or incorrect documentation
title: "[DOCS] "
labels:
- documentation
body:
- type: markdown
attributes:
value: |
## Help us improve our documentation!
Good documentation is crucial for a great developer experience. Please let us know what's missing or confusing.
- type: dropdown
id: doc_type
attributes:
label: Documentation Type
description: What kind of documentation issue is this?
options:
- Missing documentation (feature not documented)
- Unclear/confusing documentation
- Incorrect/outdated documentation
- Typo or formatting issue
- Missing code examples
- Broken links
- Other
validations:
required: true
- type: input
id: location
attributes:
label: Documentation Location
description: Where did you encounter this issue? Provide a URL if possible
placeholder: "e.g., https://docs.anthropic.com/en/docs/claude-code/getting-started"
validations:
required: false
- type: input
id: section
attributes:
label: Section/Topic
description: Which specific section or topic needs improvement?
placeholder: "e.g., MCP Server Configuration section"
validations:
required: true
- type: textarea
id: current
attributes:
label: Current Documentation
description: |
What does the documentation currently say?
Quote the specific text if applicable.
placeholder: |
The docs currently say:
"To configure MCP servers, add them to your configuration..."
But it doesn't explain...
validations:
required: false
- type: textarea
id: issue
attributes:
label: What's Wrong or Missing?
description: Explain what's incorrect, unclear, or missing
placeholder: |
The documentation doesn't explain how to:
- Configure multiple MCP servers
- Handle authentication
- Debug connection issues
The example code doesn't work because...
validations:
required: true
- type: textarea
id: suggested
attributes:
label: Suggested Improvement
description: How should the documentation be improved? Provide suggested text if possible
placeholder: |
The documentation should include:
1. A complete example showing...
2. Explanation of common errors like...
3. Step-by-step guide for...
Suggested text:
"To configure multiple MCP servers, create an array in your settings..."
validations:
required: true
- type: dropdown
id: impact
attributes:
label: Impact
description: How much does this documentation issue affect users?
options:
- High - Prevents users from using a feature
- Medium - Makes feature difficult to understand
- Low - Minor confusion or inconvenience
validations:
required: true
- type: textarea
id: additional
attributes:
label: Additional Context
description: |
- Screenshots showing the issue
- Links to related documentation
- Examples from other projects that do this well
placeholder: Any additional information that would help...
validations:
required: false

View File

@@ -0,0 +1,132 @@
name: ✨ Feature Request
description: Suggest a new feature or enhancement for Claude Code
title: "[FEATURE] "
labels:
- enhancement
body:
- type: markdown
attributes:
value: |
## Thanks for suggesting a feature!
We love hearing ideas from our community. Please help us understand your use case by filling out the sections below.
Before submitting, please check if this feature has already been requested.
- type: checkboxes
id: preflight
attributes:
label: Preflight Checklist
options:
- label: I have searched [existing requests](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20label%3Aenhancement) and this feature hasn't been requested yet
required: true
- label: This is a single feature request (not multiple features)
required: true
- type: textarea
id: problem
attributes:
label: Problem Statement
description: |
What problem are you trying to solve? Why do you need this feature?
Focus on the problem, not the solution. Help us understand your workflow.
placeholder: |
I often need to work with multiple projects simultaneously, but Claude Code doesn't support...
When I'm debugging code, I find it difficult to...
The current workflow requires me to manually...
validations:
required: true
- type: textarea
id: solution
attributes:
label: Proposed Solution
description: |
How would you like this to work? Describe the ideal user experience.
Be specific about how you'd interact with this feature.
placeholder: |
I'd like to be able to run `claude --workspace project1,project2` to...
There should be a command or setting that allows...
The interface should show...
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternative Solutions
description: |
What alternatives have you considered or tried?
Are there workarounds you're currently using?
placeholder: |
I've tried using multiple terminal windows but...
Currently I work around this by...
Other tools solve this by...
validations:
required: false
- type: dropdown
id: priority
attributes:
label: Priority
description: How important is this feature to your workflow?
options:
- Critical - Blocking my work
- High - Significant impact on productivity
- Medium - Would be very helpful
- Low - Nice to have
validations:
required: true
- type: dropdown
id: category
attributes:
label: Feature Category
description: What area does this feature relate to?
options:
- CLI commands and flags
- Interactive mode (TUI)
- File operations
- API and model interactions
- MCP server integration
- Performance and speed
- Configuration and settings
- Developer tools/SDK
- Documentation
- Other
validations:
required: true
- type: textarea
id: use_case
attributes:
label: Use Case Example
description: |
Provide a concrete, real-world example of when you'd use this feature.
Walk us through a scenario step-by-step.
placeholder: |
Example scenario:
1. I'm working on a React app with a Node.js backend
2. I need to make changes to both frontend and backend
3. With this feature, I could...
4. This would save me time because...
validations:
required: false
- type: textarea
id: additional
attributes:
label: Additional Context
description: |
- Screenshots or mockups of the proposed feature
- Links to similar features in other tools
- Technical considerations or constraints
- Any other relevant information
placeholder: Add any other context, mockups, or examples here...
validations:
required: false

View File

@@ -0,0 +1,220 @@
name: 🤖 Model Behavior Issue
description: Report unexpected Claude model behavior, incorrect actions, or permission violations
title: "[MODEL] "
labels:
- model
body:
- type: markdown
attributes:
value: |
## Report Unexpected Model Behavior
Use this template when Claude does something unexpected, makes unwanted changes, or behaves inconsistently with your instructions.
**This is for:** Unexpected actions, file modifications outside scope, ignoring instructions, making assumptions
**NOT for:** Crashes, API errors, or installation issues (use Bug Report instead)
- type: checkboxes
id: preflight
attributes:
label: Preflight Checklist
description: Please confirm before submitting
options:
- label: I have searched [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Amodel) for similar behavior reports
required: true
- label: This report does NOT contain sensitive information (API keys, passwords, etc.)
required: true
- type: dropdown
id: behavior_type
attributes:
label: Type of Behavior Issue
description: What category best describes the unexpected behavior?
options:
- Claude modified files I didn't ask it to modify
- Claude accessed files outside the working directory
- Claude ignored my instructions or configuration
- Claude reverted/undid previous changes without asking
- Claude made incorrect assumptions about my project
- Claude refused a reasonable request
- Claude's behavior changed between sessions
- Subagent behaved unexpectedly
- Other unexpected behavior
validations:
required: true
- type: textarea
id: what_you_asked
attributes:
label: What You Asked Claude to Do
description: Provide the exact prompt or command you gave
placeholder: |
I asked: "Update the README.md file to add installation instructions"
Or I ran: `claude "fix the bug in auth.js"`
validations:
required: true
- type: textarea
id: what_claude_did
attributes:
label: What Claude Actually Did
description: Describe step-by-step what Claude did instead
placeholder: |
1. Claude read README.md
2. Instead of updating it, Claude deleted the entire file
3. Created a new README from scratch with different content
4. Also modified package.json without being asked
5. Changed .gitignore file
validations:
required: true
- type: textarea
id: expected_behavior
attributes:
label: Expected Behavior
description: What should Claude have done?
placeholder: |
Claude should have:
1. Read the existing README.md
2. Added an "Installation" section
3. Only modified that single file
4. Not touched any other files
validations:
required: true
- type: textarea
id: files_affected
attributes:
label: Files Affected
description: |
List all files that were accessed or modified (even if you didn't expect them to be)
placeholder: |
Modified:
- README.md (deleted and recreated)
- package.json (version bumped - not requested)
- .gitignore (added entries - not requested)
Read (unexpectedly):
- /Users/me/.ssh/config
- ../../../parent-directory/secrets.env
render: shell
validations:
required: false
- type: dropdown
id: permission_mode
attributes:
label: Permission Mode
description: What permission settings were active?
options:
- Accept Edits was ON (auto-accepting changes)
- Accept Edits was OFF (manual approval required)
- I don't know / Not sure
validations:
required: true
- type: dropdown
id: reproducible
attributes:
label: Can You Reproduce This?
description: Does this happen consistently?
options:
- Yes, every time with the same prompt
- Sometimes (intermittent)
- No, only happened once
- Haven't tried to reproduce
validations:
required: true
- type: textarea
id: reproduction_steps
attributes:
label: Steps to Reproduce
description: If reproducible, provide minimal steps
placeholder: |
1. Create a new directory with a simple README.md
2. Ask Claude Code to "improve the README"
3. Claude will delete and recreate the file instead of editing
validations:
required: false
- type: dropdown
id: model
attributes:
label: Claude Model
description: Which model were you using? (Run `/model` to check)
options:
- Sonnet
- Opus
- Haiku
- Not sure
- Other
validations:
required: true
- type: textarea
id: conversation_log
attributes:
label: Relevant Conversation
description: |
Include relevant parts of Claude's responses, especially where it explains what it's doing
placeholder: |
Claude said: "I'll help you update the README. Let me first delete the old one and create a fresh version..."
[Then proceeded to delete without asking for confirmation]
render: markdown
validations:
required: false
- type: dropdown
id: impact
attributes:
label: Impact
description: How severe was the impact of this behavior?
options:
- Critical - Data loss or corrupted project
- High - Significant unwanted changes
- Medium - Extra work to undo changes
- Low - Minor inconvenience
validations:
required: true
- type: input
id: version
attributes:
label: Claude Code Version
description: Run `claude --version` and paste the output
placeholder: "e.g., 1.0.123 (Claude Code)"
validations:
required: true
- type: dropdown
id: platform
attributes:
label: Platform
description: Which API platform are you using?
options:
- Anthropic API
- AWS Bedrock
- Google Vertex AI
- Other
validations:
required: true
- type: textarea
id: additional
attributes:
label: Additional Context
description: |
- Any patterns you've noticed
- Similar behavior in other sessions
- Specific file types or project structures that trigger this
- Screenshots if relevant
placeholder: |
This seems to happen more often with:
- Python projects
- When there are multiple similar files
- After long conversations
validations:
required: false

View File

@@ -1,31 +0,0 @@
name: Auto-close duplicate issues
description: Auto-closes issues that are duplicates of existing issues
on:
schedule:
- cron: "0 9 * * *"
workflow_dispatch:
jobs:
auto-close-duplicates:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Auto-close duplicate issues
run: bun run scripts/auto-close-duplicates.ts
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }}
GITHUB_REPOSITORY_NAME: ${{ github.event.repository.name }}
STATSIG_API_KEY: ${{ secrets.STATSIG_API_KEY }}

View File

@@ -1,44 +0,0 @@
name: Backfill Duplicate Comments
description: Triggers duplicate detection for old issues that don't have duplicate comments
on:
workflow_dispatch:
inputs:
days_back:
description: 'How many days back to look for old issues'
required: false
default: '90'
type: string
dry_run:
description: 'Dry run mode (true to only log what would be done)'
required: false
default: 'true'
type: choice
options:
- 'true'
- 'false'
jobs:
backfill-duplicate-comments:
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
issues: read
actions: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Backfill duplicate comments
run: bun run scripts/backfill-duplicate-comments.ts
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DAYS_BACK: ${{ inputs.days_back }}
DRY_RUN: ${{ inputs.dry_run }}

View File

@@ -1,80 +0,0 @@
name: Claude Issue Dedupe
description: Automatically dedupe GitHub issues using Claude Code
on:
issues:
types: [opened]
workflow_dispatch:
inputs:
issue_number:
description: 'Issue number to process for duplicate detection'
required: true
type: string
jobs:
claude-dedupe-issues:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Run Claude Code slash command
uses: anthropics/claude-code-base-action@beta
with:
prompt: "/dedupe ${{ github.repository }}/issues/${{ github.event.issue.number || inputs.issue_number }}"
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
claude_env: |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Log duplicate comment event to Statsig
if: always()
env:
STATSIG_API_KEY: ${{ secrets.STATSIG_API_KEY }}
run: |
ISSUE_NUMBER=${{ github.event.issue.number || inputs.issue_number }}
REPO=${{ github.repository }}
if [ -z "$STATSIG_API_KEY" ]; then
echo "STATSIG_API_KEY not found, skipping Statsig logging"
exit 0
fi
# Prepare the event payload
EVENT_PAYLOAD=$(jq -n \
--arg issue_number "$ISSUE_NUMBER" \
--arg repo "$REPO" \
--arg triggered_by "${{ github.event_name }}" \
'{
events: [{
eventName: "github_duplicate_comment_added",
value: 1,
metadata: {
repository: $repo,
issue_number: ($issue_number | tonumber),
triggered_by: $triggered_by,
workflow_run_id: "${{ github.run_id }}"
},
time: (now | floor | tostring)
}]
}')
# Send to Statsig API
echo "Logging duplicate comment event to Statsig for issue #${ISSUE_NUMBER}"
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST https://events.statsigapi.net/v1/log_event \
-H "Content-Type: application/json" \
-H "STATSIG-API-KEY: ${STATSIG_API_KEY}" \
-d "$EVENT_PAYLOAD")
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | head -n-1)
if [ "$HTTP_CODE" -eq 200 ] || [ "$HTTP_CODE" -eq 202 ]; then
echo "Successfully logged duplicate comment event for issue #${ISSUE_NUMBER}"
else
echo "Failed to log duplicate comment event for issue #${ISSUE_NUMBER}. HTTP ${HTTP_CODE}: ${BODY}"
fi

View File

@@ -1,59 +0,0 @@
name: Issue Notification
on:
issues:
types: [opened]
permissions:
issues: read
jobs:
notify:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Send notification
env:
ISSUE_NUMBER: ${{ github.event.issue.number }}
ISSUE_TITLE: ${{ github.event.issue.title }}
ISSUE_BODY: ${{ github.event.issue.body }}
ISSUE_AUTHOR: ${{ github.event.issue.user.login }}
ISSUE_LABELS: ${{ toJSON(github.event.issue.labels) }}
ISSUE_URL: ${{ github.event.issue.html_url }}
ISSUE_CREATED_AT: ${{ github.event.issue.created_at }}
REPOSITORY: ${{ github.repository }}
DISPATCH_TOKEN: ${{ secrets.CROSS_REPO_TOKEN_CLAUDE_CODE }}
DISPATCH_ENDPOINT: ${{ secrets.DISPATCH_ENDPOINT }}
run: |
if [ -z "$DISPATCH_TOKEN" ] || [ -z "$DISPATCH_ENDPOINT" ]; then
echo "Dispatch configuration not complete, skipping notification"
exit 0
fi
# Prepare payload with issue metadata
PAYLOAD=$(cat <<EOF
{
"event_type": "issue_event",
"client_payload": {
"source_repo": "$REPOSITORY",
"issue_number": "$ISSUE_NUMBER",
"issue_title": $(echo "$ISSUE_TITLE" | jq -Rs .),
"issue_body": $(echo "$ISSUE_BODY" | jq -Rs .),
"issue_author": "$ISSUE_AUTHOR",
"issue_labels": $ISSUE_LABELS,
"issue_url": "$ISSUE_URL",
"issue_created_at": "$ISSUE_CREATED_AT",
"timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
}
}
EOF
)
# Send notification to configured endpoint
curl -X POST \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: token $DISPATCH_TOKEN" \
-H "Content-Type: application/json" \
"$DISPATCH_ENDPOINT" \
-d "$PAYLOAD" \
--fail-with-body || echo "Notification sent"

View File

@@ -0,0 +1,28 @@
name: Issue Opened Dispatch
on:
issues:
types: [opened]
permissions:
issues: read
actions: write
jobs:
notify:
runs-on: ubuntu-latest
timeout-minutes: 1
steps:
- name: Process new issue
env:
ISSUE_URL: ${{ github.event.issue.html_url }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
ISSUE_TITLE: ${{ github.event.issue.title }}
TARGET_REPO: ${{ secrets.ISSUE_OPENED_DISPATCH_TARGET_REPO }}
GH_TOKEN: ${{ secrets.ISSUE_OPENED_DISPATCH_TOKEN }}
run: |
gh api repos/${TARGET_REPO}/dispatches \
-f event_type=issue_opened \
-f client_payload[issue_url]="${ISSUE_URL}" || {
exit 0
}

View File

@@ -1,5 +1,9 @@
# Changelog
## 1.0.106
- Windows: Fixed path permission matching to consistently use POSIX format (e.g., `Read(//c/Users/...)`)
## 1.0.97
- Settings: /doctor now validates permission rule syntax and suggests corrections

View File

@@ -1,277 +0,0 @@
#!/usr/bin/env bun
declare global {
var process: {
env: Record<string, string | undefined>;
};
}
interface GitHubIssue {
number: number;
title: string;
user: { id: number };
created_at: string;
}
interface GitHubComment {
id: number;
body: string;
created_at: string;
user: { type: string; id: number };
}
interface GitHubReaction {
user: { id: number };
content: string;
}
async function githubRequest<T>(endpoint: string, token: string, method: string = 'GET', body?: any): Promise<T> {
const response = await fetch(`https://api.github.com${endpoint}`, {
method,
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/vnd.github.v3+json",
"User-Agent": "auto-close-duplicates-script",
...(body && { "Content-Type": "application/json" }),
},
...(body && { body: JSON.stringify(body) }),
});
if (!response.ok) {
throw new Error(
`GitHub API request failed: ${response.status} ${response.statusText}`
);
}
return response.json();
}
function extractDuplicateIssueNumber(commentBody: string): number | null {
// Try to match #123 format first
let match = commentBody.match(/#(\d+)/);
if (match) {
return parseInt(match[1], 10);
}
// Try to match GitHub issue URL format: https://github.com/owner/repo/issues/123
match = commentBody.match(/github\.com\/[^\/]+\/[^\/]+\/issues\/(\d+)/);
if (match) {
return parseInt(match[1], 10);
}
return null;
}
async function closeIssueAsDuplicate(
owner: string,
repo: string,
issueNumber: number,
duplicateOfNumber: number,
token: string
): Promise<void> {
await githubRequest(
`/repos/${owner}/${repo}/issues/${issueNumber}`,
token,
'PATCH',
{
state: 'closed',
state_reason: 'duplicate',
labels: ['duplicate']
}
);
await githubRequest(
`/repos/${owner}/${repo}/issues/${issueNumber}/comments`,
token,
'POST',
{
body: `This issue has been automatically closed as a duplicate of #${duplicateOfNumber}.
If this is incorrect, please re-open this issue or create a new one.
🤖 Generated with [Claude Code](https://claude.ai/code)`
}
);
}
async function autoCloseDuplicates(): Promise<void> {
console.log("[DEBUG] Starting auto-close duplicates script");
const token = process.env.GITHUB_TOKEN;
if (!token) {
throw new Error("GITHUB_TOKEN environment variable is required");
}
console.log("[DEBUG] GitHub token found");
const owner = process.env.GITHUB_REPOSITORY_OWNER || "anthropics";
const repo = process.env.GITHUB_REPOSITORY_NAME || "claude-code";
console.log(`[DEBUG] Repository: ${owner}/${repo}`);
const threeDaysAgo = new Date();
threeDaysAgo.setDate(threeDaysAgo.getDate() - 3);
console.log(
`[DEBUG] Checking for duplicate comments older than: ${threeDaysAgo.toISOString()}`
);
console.log("[DEBUG] Fetching open issues created more than 3 days ago...");
const allIssues: GitHubIssue[] = [];
let page = 1;
const perPage = 100;
while (true) {
const pageIssues: GitHubIssue[] = await githubRequest(
`/repos/${owner}/${repo}/issues?state=open&per_page=${perPage}&page=${page}`,
token
);
if (pageIssues.length === 0) break;
// Filter for issues created more than 3 days ago
const oldEnoughIssues = pageIssues.filter(issue =>
new Date(issue.created_at) <= threeDaysAgo
);
allIssues.push(...oldEnoughIssues);
page++;
// Safety limit to avoid infinite loops
if (page > 20) break;
}
const issues = allIssues;
console.log(`[DEBUG] Found ${issues.length} open issues`);
let processedCount = 0;
let candidateCount = 0;
for (const issue of issues) {
processedCount++;
console.log(
`[DEBUG] Processing issue #${issue.number} (${processedCount}/${issues.length}): ${issue.title}`
);
console.log(`[DEBUG] Fetching comments for issue #${issue.number}...`);
const comments: GitHubComment[] = await githubRequest(
`/repos/${owner}/${repo}/issues/${issue.number}/comments`,
token
);
console.log(
`[DEBUG] Issue #${issue.number} has ${comments.length} comments`
);
const dupeComments = comments.filter(
(comment) =>
comment.body.includes("Found") &&
comment.body.includes("possible duplicate") &&
comment.user.type === "Bot"
);
console.log(
`[DEBUG] Issue #${issue.number} has ${dupeComments.length} duplicate detection comments`
);
if (dupeComments.length === 0) {
console.log(
`[DEBUG] Issue #${issue.number} - no duplicate comments found, skipping`
);
continue;
}
const lastDupeComment = dupeComments[dupeComments.length - 1];
const dupeCommentDate = new Date(lastDupeComment.created_at);
console.log(
`[DEBUG] Issue #${
issue.number
} - most recent duplicate comment from: ${dupeCommentDate.toISOString()}`
);
if (dupeCommentDate > threeDaysAgo) {
console.log(
`[DEBUG] Issue #${issue.number} - duplicate comment is too recent, skipping`
);
continue;
}
console.log(
`[DEBUG] Issue #${
issue.number
} - duplicate comment is old enough (${Math.floor(
(Date.now() - dupeCommentDate.getTime()) / (1000 * 60 * 60 * 24)
)} days)`
);
const commentsAfterDupe = comments.filter(
(comment) => new Date(comment.created_at) > dupeCommentDate
);
console.log(
`[DEBUG] Issue #${issue.number} - ${commentsAfterDupe.length} comments after duplicate detection`
);
if (commentsAfterDupe.length > 0) {
console.log(
`[DEBUG] Issue #${issue.number} - has activity after duplicate comment, skipping`
);
continue;
}
console.log(
`[DEBUG] Issue #${issue.number} - checking reactions on duplicate comment...`
);
const reactions: GitHubReaction[] = await githubRequest(
`/repos/${owner}/${repo}/issues/comments/${lastDupeComment.id}/reactions`,
token
);
console.log(
`[DEBUG] Issue #${issue.number} - duplicate comment has ${reactions.length} reactions`
);
const authorThumbsDown = reactions.some(
(reaction) =>
reaction.user.id === issue.user.id && reaction.content === "-1"
);
console.log(
`[DEBUG] Issue #${issue.number} - author thumbs down reaction: ${authorThumbsDown}`
);
if (authorThumbsDown) {
console.log(
`[DEBUG] Issue #${issue.number} - author disagreed with duplicate detection, skipping`
);
continue;
}
const duplicateIssueNumber = extractDuplicateIssueNumber(lastDupeComment.body);
if (!duplicateIssueNumber) {
console.log(
`[DEBUG] Issue #${issue.number} - could not extract duplicate issue number from comment, skipping`
);
continue;
}
candidateCount++;
const issueUrl = `https://github.com/${owner}/${repo}/issues/${issue.number}`;
try {
console.log(
`[INFO] Auto-closing issue #${issue.number} as duplicate of #${duplicateIssueNumber}: ${issueUrl}`
);
await closeIssueAsDuplicate(owner, repo, issue.number, duplicateIssueNumber, token);
console.log(
`[SUCCESS] Successfully closed issue #${issue.number} as duplicate of #${duplicateIssueNumber}`
);
} catch (error) {
console.error(
`[ERROR] Failed to close issue #${issue.number} as duplicate: ${error}`
);
}
}
console.log(
`[DEBUG] Script completed. Processed ${processedCount} issues, found ${candidateCount} candidates for auto-close`
);
}
autoCloseDuplicates().catch(console.error);
// Make it a module
export {};

View File

@@ -1,213 +0,0 @@
#!/usr/bin/env bun
declare global {
var process: {
env: Record<string, string | undefined>;
};
}
interface GitHubIssue {
number: number;
title: string;
state: string;
state_reason?: string;
user: { id: number };
created_at: string;
closed_at?: string;
}
interface GitHubComment {
id: number;
body: string;
created_at: string;
user: { type: string; id: number };
}
async function githubRequest<T>(endpoint: string, token: string, method: string = 'GET', body?: any): Promise<T> {
const response = await fetch(`https://api.github.com${endpoint}`, {
method,
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/vnd.github.v3+json",
"User-Agent": "backfill-duplicate-comments-script",
...(body && { "Content-Type": "application/json" }),
},
...(body && { body: JSON.stringify(body) }),
});
if (!response.ok) {
throw new Error(
`GitHub API request failed: ${response.status} ${response.statusText}`
);
}
return response.json();
}
async function triggerDedupeWorkflow(
owner: string,
repo: string,
issueNumber: number,
token: string,
dryRun: boolean = true
): Promise<void> {
if (dryRun) {
console.log(`[DRY RUN] Would trigger dedupe workflow for issue #${issueNumber}`);
return;
}
await githubRequest(
`/repos/${owner}/${repo}/actions/workflows/claude-dedupe-issues.yml/dispatches`,
token,
'POST',
{
ref: 'main',
inputs: {
issue_number: issueNumber.toString()
}
}
);
}
async function backfillDuplicateComments(): Promise<void> {
console.log("[DEBUG] Starting backfill duplicate comments script");
const token = process.env.GITHUB_TOKEN;
if (!token) {
throw new Error(`GITHUB_TOKEN environment variable is required
Usage:
GITHUB_TOKEN=your_token bun run scripts/backfill-duplicate-comments.ts
Environment Variables:
GITHUB_TOKEN - GitHub personal access token with repo and actions permissions (required)
DRY_RUN - Set to "false" to actually trigger workflows (default: true for safety)
MAX_ISSUE_NUMBER - Only process issues with numbers less than this value (default: 4050)`);
}
console.log("[DEBUG] GitHub token found");
const owner = "anthropics";
const repo = "claude-code";
const dryRun = process.env.DRY_RUN !== "false";
const maxIssueNumber = parseInt(process.env.MAX_ISSUE_NUMBER || "4050", 10);
const minIssueNumber = parseInt(process.env.MIN_ISSUE_NUMBER || "1", 10);
console.log(`[DEBUG] Repository: ${owner}/${repo}`);
console.log(`[DEBUG] Dry run mode: ${dryRun}`);
console.log(`[DEBUG] Looking at issues between #${minIssueNumber} and #${maxIssueNumber}`);
console.log(`[DEBUG] Fetching issues between #${minIssueNumber} and #${maxIssueNumber}...`);
const allIssues: GitHubIssue[] = [];
let page = 1;
const perPage = 100;
while (true) {
const pageIssues: GitHubIssue[] = await githubRequest(
`/repos/${owner}/${repo}/issues?state=all&per_page=${perPage}&page=${page}&sort=created&direction=desc`,
token
);
if (pageIssues.length === 0) break;
// Filter to only include issues within the specified range
const filteredIssues = pageIssues.filter(issue =>
issue.number >= minIssueNumber && issue.number < maxIssueNumber
);
allIssues.push(...filteredIssues);
// If the oldest issue in this page is still above our minimum, we need to continue
// but if the oldest issue is below our minimum, we can stop
const oldestIssueInPage = pageIssues[pageIssues.length - 1];
if (oldestIssueInPage && oldestIssueInPage.number >= maxIssueNumber) {
console.log(`[DEBUG] Oldest issue in page #${page} is #${oldestIssueInPage.number}, continuing...`);
} else if (oldestIssueInPage && oldestIssueInPage.number < minIssueNumber) {
console.log(`[DEBUG] Oldest issue in page #${page} is #${oldestIssueInPage.number}, below minimum, stopping`);
break;
} else if (filteredIssues.length === 0 && pageIssues.length > 0) {
console.log(`[DEBUG] No issues in page #${page} are in range #${minIssueNumber}-#${maxIssueNumber}, continuing...`);
}
page++;
// Safety limit to avoid infinite loops
if (page > 200) {
console.log("[DEBUG] Reached page limit, stopping pagination");
break;
}
}
console.log(`[DEBUG] Found ${allIssues.length} issues between #${minIssueNumber} and #${maxIssueNumber}`);
let processedCount = 0;
let candidateCount = 0;
let triggeredCount = 0;
for (const issue of allIssues) {
processedCount++;
console.log(
`[DEBUG] Processing issue #${issue.number} (${processedCount}/${allIssues.length}): ${issue.title}`
);
console.log(`[DEBUG] Fetching comments for issue #${issue.number}...`);
const comments: GitHubComment[] = await githubRequest(
`/repos/${owner}/${repo}/issues/${issue.number}/comments`,
token
);
console.log(
`[DEBUG] Issue #${issue.number} has ${comments.length} comments`
);
// Look for existing duplicate detection comments (from the dedupe bot)
const dupeDetectionComments = comments.filter(
(comment) =>
comment.body.includes("Found") &&
comment.body.includes("possible duplicate") &&
comment.user.type === "Bot"
);
console.log(
`[DEBUG] Issue #${issue.number} has ${dupeDetectionComments.length} duplicate detection comments`
);
// Skip if there's already a duplicate detection comment
if (dupeDetectionComments.length > 0) {
console.log(
`[DEBUG] Issue #${issue.number} already has duplicate detection comment, skipping`
);
continue;
}
candidateCount++;
const issueUrl = `https://github.com/${owner}/${repo}/issues/${issue.number}`;
try {
console.log(
`[INFO] ${dryRun ? '[DRY RUN] ' : ''}Triggering dedupe workflow for issue #${issue.number}: ${issueUrl}`
);
await triggerDedupeWorkflow(owner, repo, issue.number, token, dryRun);
if (!dryRun) {
console.log(
`[SUCCESS] Successfully triggered dedupe workflow for issue #${issue.number}`
);
}
triggeredCount++;
} catch (error) {
console.error(
`[ERROR] Failed to trigger workflow for issue #${issue.number}: ${error}`
);
}
// Add a delay between workflow triggers to avoid overwhelming the system
await new Promise(resolve => setTimeout(resolve, 1000));
}
console.log(
`[DEBUG] Script completed. Processed ${processedCount} issues, found ${candidateCount} candidates without duplicate comments, ${dryRun ? 'would trigger' : 'triggered'} ${triggeredCount} workflows`
);
}
backfillDuplicateComments().catch(console.error);
// Make it a module
export {};