diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index d0601412c0..44549d03d5 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -1,5 +1,5 @@ { - "$schema": "https://anthropic.com/claude-code/marketplace.schema.json", + "$schema": "https://json.schemastore.org/claude-code-marketplace.json", "name": "claude-code-plugins", "version": "1.0.0", "description": "Bundled plugins for Claude Code including Agent SDK development tools, PR review toolkit, and commit workflows", diff --git a/.claude/commands/dedupe.md b/.claude/commands/dedupe.md index 6641b5d88c..d83fa2793b 100644 --- a/.claude/commands/dedupe.md +++ b/.claude/commands/dedupe.md @@ -1,5 +1,5 @@ --- -allowed-tools: Bash(gh issue view:*), Bash(gh search:*), Bash(gh issue list:*), Bash(./scripts/comment-on-duplicates.sh:*) +allowed-tools: Bash(./scripts/gh.sh:*), Bash(./scripts/comment-on-duplicates.sh:*) description: Find duplicate GitHub issues --- @@ -13,11 +13,15 @@ To do this, follow these steps precisely: 4. Next, feed the results from #1 and #2 into another agent, so that it can filter out false positives, that are likely not actually duplicates of the original issue. If there are no duplicates remaining, do not proceed. 5. Finally, use the comment script to post duplicates: ``` - ./scripts/comment-on-duplicates.sh --base-issue --potential-duplicates + ./scripts/comment-on-duplicates.sh --potential-duplicates ``` Notes (be sure to tell this to your agents, too): -- Use `gh` to interact with Github, rather than web fetch -- Do not use other tools, beyond `gh` and the comment script (eg. don't use other MCP servers, file edit, etc.) +- Use `./scripts/gh.sh` to interact with Github, rather than web fetch or raw `gh`. Examples: + - `./scripts/gh.sh issue view 123` — view an issue + - `./scripts/gh.sh issue view 123 --comments` — view with comments + - `./scripts/gh.sh issue list --state open --limit 20` — list issues + - `./scripts/gh.sh search issues "query" --limit 10` — search for issues +- Do not use other tools, beyond `./scripts/gh.sh` and the comment script (eg. don't use other MCP servers, file edit, etc.) - Make a todo list first diff --git a/.claude/commands/oncall-triage.md b/.claude/commands/oncall-triage.md deleted file mode 100644 index 979bdfe6e2..0000000000 --- a/.claude/commands/oncall-triage.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -allowed-tools: Bash(gh issue list:*), Bash(gh issue view:*), Bash(gh issue edit:*), TodoWrite -description: Triage GitHub issues and label critical ones for oncall ---- - -You're an oncall triage assistant for GitHub issues. Your task is to identify critical issues that require immediate oncall attention and apply the "oncall" label. - -Repository: anthropics/claude-code - -Task overview: - -1. First, get all open bugs updated in the last 3 days with at least 50 engagements: - ```bash - gh issue list --repo anthropics/claude-code --state open --label bug --limit 1000 --json number,title,updatedAt,comments,reactions | jq -r '.[] | select((.updatedAt >= (now - 259200 | strftime("%Y-%m-%dT%H:%M:%SZ"))) and ((.comments | length) + ([.reactions[].content] | length) >= 50)) | "\(.number)"' - ``` - -2. Save the list of issue numbers and create a TODO list with ALL of them. This ensures you process every single one. - -3. For each issue in your TODO list: - - Use `gh issue view --repo anthropics/claude-code --json title,body,labels,comments` to get full details - - Read and understand the full issue content and comments to determine actual user impact - - Evaluate: Is this truly blocking users from using Claude Code? - - Consider: "crash", "stuck", "frozen", "hang", "unresponsive", "cannot use", "blocked", "broken" - - Does it prevent core functionality? Can users work around it? - - Be conservative - only flag issues that truly prevent users from getting work done - -4. For issues that are truly blocking and don't already have the "oncall" label: - - Use `gh issue edit --repo anthropics/claude-code --add-label "oncall"` - - Mark the issue as complete in your TODO list - -5. After processing all issues, provide a summary: - - List each issue number that received the "oncall" label - - Include the issue title and brief reason why it qualified - - If no issues qualified, state that clearly - -Important: -- Process ALL issues in your TODO list systematically -- Don't post any comments to issues -- Only add the "oncall" label, never remove it -- Use individual `gh issue view` commands instead of bash for loops to avoid approval prompts diff --git a/.claude/commands/triage-issue.md b/.claude/commands/triage-issue.md new file mode 100644 index 0000000000..4d63784bb2 --- /dev/null +++ b/.claude/commands/triage-issue.md @@ -0,0 +1,74 @@ +--- +allowed-tools: Bash(./scripts/gh.sh:*),Bash(./scripts/edit-issue-labels.sh:*) +description: Triage GitHub issues by analyzing and applying labels +--- + +You're an issue triage assistant. Analyze the issue and manage labels. + +IMPORTANT: Don't post any comments or messages to the issue. Your only actions are adding or removing labels. + +Context: + +$ARGUMENTS + +TOOLS: +- `./scripts/gh.sh` — wrapper for `gh` CLI. Only supports these subcommands and flags: + - `./scripts/gh.sh label list` — fetch all available labels + - `./scripts/gh.sh label list --limit 100` — fetch with limit + - `./scripts/gh.sh issue view 123` — read issue title, body, and labels + - `./scripts/gh.sh issue view 123 --comments` — read the conversation + - `./scripts/gh.sh issue list --state open --limit 20` — list issues + - `./scripts/gh.sh search issues "query"` — find similar or duplicate issues + - `./scripts/gh.sh search issues "query" --limit 10` — search with limit +- `./scripts/edit-issue-labels.sh --add-label LABEL --remove-label LABEL` — add or remove labels (issue number is read from the workflow event) + +TASK: + +1. Run `./scripts/gh.sh label list` to fetch the available labels. You may ONLY use labels from this list. Never invent new labels. +2. Run `./scripts/gh.sh issue view ISSUE_NUMBER` to read the issue details. +3. Run `./scripts/gh.sh issue view ISSUE_NUMBER --comments` to read the conversation. + +**If EVENT is "issues" (new issue):** + +4. First, check if this issue is actually about Claude Code. + - Look for Claude Code signals in the issue BODY: a `Claude Code Version` field or `claude --version` output, references to the `claude` CLI command, terminal sessions, the VS Code/JetBrains extensions, `CLAUDE.md` files, `.claude/` directories, MCP servers, Cowork, Remote Control, or the web UI at claude.ai/code. If ANY such signal is present, this IS a Claude Code issue — proceed to step 5. + - Only if NO Claude Code signals are present: check whether a different Anthropic product (claude.ai chat, Claude Desktop/Mobile apps, the raw Anthropic API/SDK, or account billing with no CLI involvement) is the *subject* of the complaint, not merely mentioned for context. If so, apply `invalid` and stop. If ambiguous, proceed to step 5 WITHOUT applying `invalid`. + - The body text is authoritative. If a form dropdown (e.g. Platform) contradicts evidence in the body, trust the body — dropdowns are often mis-selected. + +5. Analyze and apply category labels: + - Type (bug, enhancement, question, etc.) + - Technical areas and platform + - Check for duplicates with `./scripts/gh.sh search issues`. Only mark as duplicate of OPEN issues. + +6. Evaluate lifecycle labels: + - `needs-repro` (bugs only, 7 days): Bug reports without clear steps to reproduce. A good repro has specific, followable steps that someone else could use to see the same issue. + Do NOT apply if the user already provided error messages, logs, file paths, or a description of what they did. Don't require a specific format — narrative descriptions count. + For model behavior issues (e.g. "Claude does X when it should do Y"), don't require traditional repro steps — examples and patterns are sufficient. + - `needs-info` (bugs only, 7 days): The issue needs something from the community before it can progress — e.g. error messages, versions, environment details, or answers to follow-up questions. Don't apply to questions or enhancements. + Do NOT apply if the user already provided version, environment, and error details. If the issue just needs engineering investigation, that's not `needs-info`. + + Issues with these labels are automatically closed after the timeout if there's no response. + The goal is to avoid issues lingering without a clear next step. + +7. Apply all selected labels: + `./scripts/edit-issue-labels.sh --add-label "label1" --add-label "label2"` + +**If EVENT is "issue_comment" (comment on existing issue):** + +4. Evaluate lifecycle labels based on the full conversation: + - If the issue has `stale` or `autoclose`, remove the label — a new human comment means the issue is still active: + `./scripts/edit-issue-labels.sh --remove-label "stale" --remove-label "autoclose"` + - If the issue has `needs-repro` or `needs-info` and the missing information has now been provided, remove the label: + `./scripts/edit-issue-labels.sh --remove-label "needs-repro"` + - If the issue doesn't have lifecycle labels but clearly needs them (e.g., a maintainer asked for repro steps or more details), add the appropriate label. + - Comments like "+1", "me too", "same here", or emoji reactions are NOT the missing information. Only remove `needs-repro` or `needs-info` when substantive details are actually provided. + - Do NOT add or remove category labels (bug, enhancement, etc.) on comment events. + +GUIDELINES: +- ONLY use labels from `./scripts/gh.sh label list` — never create or guess label names +- DO NOT post any comments to the issue +- Be conservative with lifecycle labels — only apply when clearly warranted +- Only apply lifecycle labels (`needs-repro`, `needs-info`) to bugs — never to questions or enhancements +- When in doubt, don't apply a lifecycle label — false positives are worse than missing labels +- On new issues (EVENT "issues"), always apply exactly one of `bug`, `enhancement`, `question`, `invalid`, or `duplicate`. If unsure, pick the closest fit — an imperfect category label is better than none. +- On comment events, it's okay to make no changes if nothing applies. diff --git a/.github/workflows/auto-close-duplicates.yml b/.github/workflows/auto-close-duplicates.yml index b6ca0563fe..7f67a057ab 100644 --- a/.github/workflows/auto-close-duplicates.yml +++ b/.github/workflows/auto-close-duplicates.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Bun - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 (sha-pinned) with: bun-version: latest diff --git a/.github/workflows/backfill-duplicate-comments.yml b/.github/workflows/backfill-duplicate-comments.yml index acce8f9088..16a39b977b 100644 --- a/.github/workflows/backfill-duplicate-comments.yml +++ b/.github/workflows/backfill-duplicate-comments.yml @@ -32,7 +32,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Bun - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 (sha-pinned) with: bun-version: latest diff --git a/.github/workflows/claude-dedupe-issues.yml b/.github/workflows/claude-dedupe-issues.yml index 13385e96cd..cfbdf2db23 100644 --- a/.github/workflows/claude-dedupe-issues.yml +++ b/.github/workflows/claude-dedupe-issues.yml @@ -17,6 +17,7 @@ jobs: permissions: contents: read issues: write + # Required to mint the OIDC token exchanged for a Claude API access token (Workload Identity Federation) id-token: write steps: @@ -27,21 +28,29 @@ jobs: uses: anthropics/claude-code-action@v1 env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CLAUDE_CODE_SCRIPT_CAPS: '{"comment-on-duplicates.sh":1}' with: github_token: ${{ secrets.GITHUB_TOKEN }} allowed_non_write_users: "*" prompt: "/dedupe ${{ github.repository }}/issues/${{ github.event.issue.number || inputs.issue_number }}" - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + # Authenticate to the Claude API via Workload Identity Federation + # (the workflow's OIDC token is exchanged for a short-lived access + # token) instead of a static API key. + anthropic_federation_rule_id: ${{ vars.ANTHROPIC_FEDERATION_RULE_ID }} + anthropic_organization_id: ${{ vars.ANTHROPIC_ORGANIZATION_ID }} + anthropic_service_account_id: ${{ vars.ANTHROPIC_SERVICE_ACCOUNT_ID }} + anthropic_workspace_id: ${{ vars.ANTHROPIC_WORKSPACE_ID }} claude_args: "--model claude-sonnet-4-5-20250929" - name: Log duplicate comment event to Statsig if: always() env: STATSIG_API_KEY: ${{ secrets.STATSIG_API_KEY }} + ISSUE_NUMBER: ${{ github.event.issue.number || inputs.issue_number }} + REPO: ${{ github.repository }} + TRIGGERED_BY: ${{ github.event_name }} + WORKFLOW_RUN_ID: ${{ github.run_id }} 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 @@ -51,7 +60,8 @@ jobs: EVENT_PAYLOAD=$(jq -n \ --arg issue_number "$ISSUE_NUMBER" \ --arg repo "$REPO" \ - --arg triggered_by "${{ github.event_name }}" \ + --arg triggered_by "$TRIGGERED_BY" \ + --arg workflow_run_id "$WORKFLOW_RUN_ID" \ '{ events: [{ eventName: "github_duplicate_comment_added", @@ -60,7 +70,7 @@ jobs: repository: $repo, issue_number: ($issue_number | tonumber), triggered_by: $triggered_by, - workflow_run_id: "${{ github.run_id }}" + workflow_run_id: $workflow_run_id }, time: (now | floor | tostring) }] diff --git a/.github/workflows/claude-issue-triage.yml b/.github/workflows/claude-issue-triage.yml index 02695ad8b8..6c667e2d8a 100644 --- a/.github/workflows/claude-issue-triage.yml +++ b/.github/workflows/claude-issue-triage.yml @@ -1,105 +1,47 @@ name: Claude Issue Triage -description: Automatically triage GitHub issues using Claude Code on: issues: types: [opened] + issue_comment: + types: [created] jobs: triage-issue: runs-on: ubuntu-latest timeout-minutes: 10 + if: >- + github.event_name == 'issues' || + (github.event_name == 'issue_comment' && !github.event.issue.pull_request && github.event.comment.user.type != 'Bot') + concurrency: + group: issue-triage-${{ github.event.issue.number }} + cancel-in-progress: true permissions: contents: read issues: write + # Required to mint the OIDC token exchanged for a Claude API access token (Workload Identity Federation) id-token: write steps: - name: Checkout repository uses: actions/checkout@v4 - - name: Setup GitHub MCP Server - run: | - mkdir -p /tmp/mcp-config - cat > /tmp/mcp-config/mcp-servers.json << 'EOF' - { - "mcpServers": { - "github": { - "command": "docker", - "args": [ - "run", - "-i", - "--rm", - "-e", - "GITHUB_PERSONAL_ACCESS_TOKEN", - "ghcr.io/github/github-mcp-server:sha-7aced2b" - ], - "env": { - "GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}" - } - } - } - } - EOF - - name: Run Claude Code for Issue Triage timeout-minutes: 5 uses: anthropics/claude-code-action@v1 env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + CLAUDE_CODE_SCRIPT_CAPS: '{"edit-issue-labels.sh":2}' with: github_token: ${{ secrets.GITHUB_TOKEN }} allowed_non_write_users: "*" - prompt: | - You're an issue triage assistant for GitHub issues. Your task is to analyze the issue and select appropriate labels from the provided list. - - IMPORTANT: Don't post any comments or messages to the issue. Your only action should be to apply labels. - - Issue Information: - - REPO: ${{ github.repository }} - - ISSUE_NUMBER: ${{ github.event.issue.number }} - - TASK OVERVIEW: - - 1. First, fetch the list of labels available in this repository by running: `gh label list`. Run exactly this command with nothing else. - - 2. Next, use the GitHub tools to get context about the issue: - - You have access to these tools: - - mcp__github__get_issue: Use this to retrieve the current issue's details including title, description, and existing labels - - mcp__github__get_issue_comments: Use this to read any discussion or additional context provided in the comments - - mcp__github__update_issue: Use this to apply labels to the issue (do not use this for commenting) - - mcp__github__search_issues: Use this to find similar issues that might provide context for proper categorization and to identify potential duplicate issues - - mcp__github__list_issues: Use this to understand patterns in how other issues are labeled - - Start by using mcp__github__get_issue to get the issue details - - 3. Analyze the issue content, considering: - - The issue title and description - - The type of issue (bug report, feature request, question, etc.) - - Technical areas mentioned - - Severity or priority indicators - - User impact - - Components affected - - 4. Select appropriate labels from the available labels list provided above: - - Choose labels that accurately reflect the issue's nature - - Be specific but comprehensive - - Select priority labels if you can determine urgency (high-priority, med-priority, or low-priority) - - Consider platform labels (android, ios) if applicable - - If you find similar issues using mcp__github__search_issues, consider using a "duplicate" label if appropriate. Only do so if the issue is a duplicate of another OPEN issue. - - 5. Apply the selected labels: - - Use mcp__github__update_issue to apply your selected labels - - DO NOT post any comments explaining your decision - - DO NOT communicate directly with users - - If no labels are clearly applicable, do not apply any labels - - IMPORTANT GUIDELINES: - - Be thorough in your analysis - - Only select labels from the provided list above - - DO NOT post any comments to the issue - - Your ONLY action should be to apply labels using mcp__github__update_issue - - It's okay to not add any labels if none are clearly applicable - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + prompt: "/triage-issue REPO: ${{ github.repository }} ISSUE_NUMBER: ${{ github.event.issue.number }} EVENT: ${{ github.event_name }}" + # Authenticate to the Claude API via Workload Identity Federation + # (the workflow's OIDC token is exchanged for a short-lived access + # token) instead of a static API key. + anthropic_federation_rule_id: ${{ vars.ANTHROPIC_FEDERATION_RULE_ID }} + anthropic_organization_id: ${{ vars.ANTHROPIC_ORGANIZATION_ID }} + anthropic_service_account_id: ${{ vars.ANTHROPIC_SERVICE_ACCOUNT_ID }} + anthropic_workspace_id: ${{ vars.ANTHROPIC_WORKSPACE_ID }} claude_args: | - --model claude-sonnet-4-5-20250929 - --mcp-config /tmp/mcp-config/mcp-servers.json - --allowedTools "Bash(gh label list),mcp__github__get_issue,mcp__github__get_issue_comments,mcp__github__update_issue,mcp__github__search_issues,mcp__github__list_issues" + --model claude-opus-4-6 diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index d469b0e7b9..e2348761f1 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -33,6 +33,12 @@ jobs: id: claude uses: anthropics/claude-code-action@v1 with: - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + # Authenticate to the Claude API via Workload Identity Federation + # (the workflow's OIDC token is exchanged for a short-lived access + # token) instead of a static API key. + anthropic_federation_rule_id: ${{ vars.ANTHROPIC_FEDERATION_RULE_ID }} + anthropic_organization_id: ${{ vars.ANTHROPIC_ORGANIZATION_ID }} + anthropic_service_account_id: ${{ vars.ANTHROPIC_SERVICE_ACCOUNT_ID }} + anthropic_workspace_id: ${{ vars.ANTHROPIC_WORKSPACE_ID }} claude_args: "--model claude-sonnet-4-5-20250929" diff --git a/.github/workflows/issue-lifecycle-comment.yml b/.github/workflows/issue-lifecycle-comment.yml new file mode 100644 index 0000000000..1acffef2e4 --- /dev/null +++ b/.github/workflows/issue-lifecycle-comment.yml @@ -0,0 +1,27 @@ +name: "Issue Lifecycle Comment" + +on: + issues: + types: [labeled] + +permissions: + issues: write + +jobs: + comment: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 (sha-pinned) + with: + bun-version: latest + + - name: Post lifecycle comment + run: bun run scripts/lifecycle-comment.ts + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + LABEL: ${{ github.event.label.name }} + ISSUE_NUMBER: ${{ github.event.issue.number }} diff --git a/.github/workflows/non-write-users-check.yml b/.github/workflows/non-write-users-check.yml new file mode 100644 index 0000000000..584bc7ddb3 --- /dev/null +++ b/.github/workflows/non-write-users-check.yml @@ -0,0 +1,47 @@ +name: Non-write Users Check +on: + pull_request: + paths: + - ".github/**" + +permissions: + contents: read + pull-requests: write + +jobs: + allowed-non-write-check: + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - run: | + DIFF=$(gh pr diff "$PR_NUMBER" -R "$REPO" || true) + + if ! echo "$DIFF" | grep -qE '^diff --git a/\.github/.*\.ya?ml'; then + exit 0 + fi + + MATCHES=$(echo "$DIFF" | grep "^+.*allowed_non_write_users" || true) + + if [ -z "$MATCHES" ]; then + exit 0 + fi + + EXISTING=$(gh pr view "$PR_NUMBER" -R "$REPO" --json comments --jq '.comments[].body' \ + | grep -c "" || true) + + if [ "$EXISTING" -gt 0 ]; then + exit 0 + fi + + gh pr comment "$PR_NUMBER" -R "$REPO" --body ' + **`allowed_non_write_users` detected** + + This PR adds or modifies `allowed_non_write_users`, which allows users without write access to trigger Claude Code Action workflows. This can introduce security risks. + + If this is a new flow, please make sure you actually need `allowed_non_write_users`. If you are editing an existing workflow, double check that you are not adding new Claude permissions which might lead to a vulnerability. + + See existing workflows in this repo for safe usage examples, or contact the AppSec team.' + env: + PR_NUMBER: ${{ github.event.pull_request.number }} + REPO: ${{ github.repository }} diff --git a/.github/workflows/oncall-triage.yml b/.github/workflows/oncall-triage.yml deleted file mode 100644 index d70d415e44..0000000000 --- a/.github/workflows/oncall-triage.yml +++ /dev/null @@ -1,118 +0,0 @@ -name: Oncall Issue Triage -description: Automatically identify and label critical blocking issues requiring oncall attention -on: - push: - branches: - - add-oncall-triage-workflow # Temporary: for testing only - schedule: - # Run every 6 hours - - cron: '0 */6 * * *' - workflow_dispatch: # Allow manual trigger - -jobs: - oncall-triage: - runs-on: ubuntu-latest - timeout-minutes: 15 - permissions: - contents: read - issues: write - id-token: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup GitHub MCP Server - run: | - mkdir -p /tmp/mcp-config - cat > /tmp/mcp-config/mcp-servers.json << 'EOF' - { - "mcpServers": { - "github": { - "command": "docker", - "args": [ - "run", - "-i", - "--rm", - "-e", - "GITHUB_PERSONAL_ACCESS_TOKEN", - "ghcr.io/github/github-mcp-server:sha-7aced2b" - ], - "env": { - "GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}" - } - } - } - } - EOF - - - name: Run Claude Code for Oncall Triage - timeout-minutes: 10 - uses: anthropics/claude-code-action@v1 - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - allowed_non_write_users: "*" - prompt: | - You're an oncall triage assistant for GitHub issues. Your task is to identify critical issues that require immediate oncall attention. - - Important: Don't post any comments or messages to the issues. Your only action should be to apply the "oncall" label to qualifying issues. - - Repository: ${{ github.repository }} - - Task overview: - 1. Fetch all open issues updated in the last 3 days: - - Use mcp__github__list_issues with: - - state="open" - - first=5 (fetch only 5 issues per page) - - orderBy="UPDATED_AT" - - direction="DESC" - - This will give you the most recently updated issues first - - For each page of results, check the updatedAt timestamp of each issue - - Add issues updated within the last 3 days (72 hours) to your TODO list as you go - - Keep paginating using the 'after' parameter until you encounter issues older than 3 days - - Once you hit issues older than 3 days, you can stop fetching (no need to fetch all open issues) - - 2. Build your TODO list incrementally as you fetch: - - As you fetch each page, immediately add qualifying issues to your TODO list - - One TODO item per issue number (e.g., "Evaluate issue #123") - - This allows you to start processing while still fetching more pages - - 3. For each issue in your TODO list: - - Use mcp__github__get_issue to read the issue details (title, body, labels) - - Use mcp__github__get_issue_comments to read all comments - - Evaluate whether this issue needs the oncall label: - a) Is it a bug? (has "bug" label or describes bug behavior) - b) Does it have at least 50 engagements? (count comments + reactions) - c) Is it truly blocking? Read and understand the full content to determine: - - Does this prevent core functionality from working? - - Can users work around it? - - Consider severity indicators: "crash", "stuck", "frozen", "hang", "unresponsive", "cannot use", "blocked", "broken" - - Be conservative - only flag issues that truly prevent users from getting work done - - 4. For issues that meet all criteria and do not already have the "oncall" label: - - Use mcp__github__update_issue to add the "oncall" label - - Do not post any comments - - Do not remove any existing labels - - Do not remove the "oncall" label from issues that already have it - - Important guidelines: - - Use the TODO list to track your progress through ALL candidate issues - - Process issues efficiently - don't read every single issue upfront, work through your TODO list systematically - - Be conservative in your assessment - only flag truly critical blocking issues - - Do not post any comments to issues - - Your only action should be to add the "oncall" label using mcp__github__update_issue - - Mark each issue as complete in your TODO list as you process it - - 7. After processing all issues in your TODO list, provide a summary of your actions: - - Total number of issues processed (candidate issues evaluated) - - Number of issues that received the "oncall" label - - For each issue that got the label: list issue number, title, and brief reason why it qualified - - Close calls: List any issues that almost qualified but didn't quite meet the criteria (e.g., borderline blocking, had workarounds) - - If no issues qualified, state that clearly - - Format the summary clearly for easy reading - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - claude_args: | - --mcp-config /tmp/mcp-config/mcp-servers.json - --allowedTools "mcp__github__list_issues,mcp__github__get_issue,mcp__github__get_issue_comments,mcp__github__update_issue" diff --git a/.github/workflows/stale-issue-manager.yml b/.github/workflows/stale-issue-manager.yml deleted file mode 100644 index 7da781377f..0000000000 --- a/.github/workflows/stale-issue-manager.yml +++ /dev/null @@ -1,157 +0,0 @@ -name: "Manage Stale Issues" - -on: - schedule: - # 2am Pacific = 9am UTC (10am UTC during DST) - - cron: "0 10 * * *" - workflow_dispatch: - -permissions: - issues: write - -concurrency: - group: stale-issue-manager - -jobs: - manage-stale-issues: - runs-on: ubuntu-latest - steps: - - name: Manage stale issues - uses: actions/github-script@v7 - with: - script: | - const oneMonthAgo = new Date(); - oneMonthAgo.setDate(oneMonthAgo.getDate() - 30); - - const twoMonthsAgo = new Date(); - twoMonthsAgo.setDate(twoMonthsAgo.getDate() - 60); - - const warningComment = `This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.`; - - const closingComment = `This issue has been automatically closed due to 60 days of inactivity. If you're still experiencing this issue, please open a new issue with updated information.`; - - let page = 1; - let hasMore = true; - let totalWarned = 0; - let totalClosed = 0; - let totalLabeled = 0; - - while (hasMore) { - // Get open issues sorted by last updated (oldest first) - const { data: issues } = await github.rest.issues.listForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - state: 'open', - sort: 'updated', - direction: 'asc', - per_page: 100, - page: page - }); - - if (issues.length === 0) { - hasMore = false; - break; - } - - for (const issue of issues) { - // Skip if already locked - if (issue.locked) continue; - - // Skip pull requests - if (issue.pull_request) continue; - - // Check if updated more recently than 30 days ago - const updatedAt = new Date(issue.updated_at); - if (updatedAt > oneMonthAgo) { - // Since issues are sorted by updated_at ascending, - // once we hit a recent issue, all remaining will be recent too - hasMore = false; - break; - } - - // Check if issue has autoclose label - const hasAutocloseLabel = issue.labels.some(label => - typeof label === 'object' && label.name === 'autoclose' - ); - - try { - // Get comments to check for existing warning - const { data: comments } = await github.rest.issues.listComments({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - per_page: 100 - }); - - // Find the last comment from github-actions bot - const botComments = comments.filter(comment => - comment.user && comment.user.login === 'github-actions[bot]' && - comment.body && comment.body.includes('inactive for 30 days') - ); - - const lastBotComment = botComments[botComments.length - 1]; - - if (lastBotComment) { - // Check if the bot comment is older than 30 days (total 60 days of inactivity) - const botCommentDate = new Date(lastBotComment.created_at); - if (botCommentDate < oneMonthAgo) { - // Close the issue - it's been stale for 60+ days - console.log(`Closing issue #${issue.number} (stale for 60+ days): ${issue.title}`); - - // Post closing comment - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - body: closingComment - }); - - // Close the issue - await github.rest.issues.update({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - state: 'closed', - state_reason: 'not_planned' - }); - - totalClosed++; - } - // If bot comment exists but is recent, issue already has warning - } else if (updatedAt < oneMonthAgo) { - // No bot warning yet, issue is 30+ days old - console.log(`Warning issue #${issue.number} (stale for 30+ days): ${issue.title}`); - - // Post warning comment - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - body: warningComment - }); - - totalWarned++; - - // Add autoclose label if not present - if (!hasAutocloseLabel) { - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - labels: ['autoclose'] - }); - totalLabeled++; - } - } - } catch (error) { - console.error(`Failed to process issue #${issue.number}: ${error.message}`); - } - } - - page++; - } - - console.log(`Summary:`); - console.log(`- Issues warned (30 days stale): ${totalWarned}`); - console.log(`- Issues labeled with autoclose: ${totalLabeled}`); - console.log(`- Issues closed (60 days stale): ${totalClosed}`); diff --git a/.github/workflows/sweep.yml b/.github/workflows/sweep.yml new file mode 100644 index 0000000000..345616b409 --- /dev/null +++ b/.github/workflows/sweep.yml @@ -0,0 +1,31 @@ +name: "Issue Sweep" + +on: + schedule: + - cron: "0 10,22 * * *" + workflow_dispatch: + +permissions: + issues: write + +concurrency: + group: daily-issue-sweep + +jobs: + sweep: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 (sha-pinned) + with: + bun-version: latest + + - name: Enforce lifecycle timeouts + run: bun run scripts/sweep.ts + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }} + GITHUB_REPOSITORY_NAME: ${{ github.event.repository.name }} diff --git a/CHANGELOG.md b/CHANGELOG.md index d19852e127..761d992791 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,2384 @@ # Changelog +## 2.1.152 + +- `/code-review --fix` now applies review findings to your working tree after the review, surfacing reuse, simplification, and efficiency suggestions; `/simplify` now invokes `/code-review --fix` +- Skills and slash commands can now set `disallowed-tools` in frontmatter to remove tools from the model while the skill is active +- Added `/reload-skills` command to re-scan skill directories without restarting the session +- `SessionStart` hooks can now return `reloadSkills: true` to re-scan skill directories, making skills installed by the hook available in the same session +- `SessionStart` hooks can now set the session title via `hookSpecificOutput.sessionTitle` on startup and resume +- Added a `MessageDisplay` hook event that lets hooks transform or hide assistant message text as it is displayed +- Added `pluginSuggestionMarketplaces` managed setting: admins can allowlist org marketplaces whose plugins may be suggested via context-aware tips +- `claude plugin marketplace remove` now accepts `--scope user|project|local` for symmetry with `marketplace add`, `install`, and `uninstall` +- Claude Code now switches to your configured `--fallback-model` for the rest of the session when the primary model is not found, instead of failing every request +- Auto mode no longer requires opt-in consent +- Vim mode: `/` in NORMAL mode now opens reverse history search (like Ctrl+R), matching bash/zsh vi-mode +- The `/usage` breakdown now includes large session files; files are scanned with a streaming read so memory usage stays flat +- Thinking summaries in the collapsed group now stay readable for at least 3 seconds, render as markdown, and cap at 10 lines (`Ctrl+O` shows the full thinking) +- In fullscreen mode, the "Thinking for Ns" indicator now counts up live while the model is thinking, and keeps its value if you interrupt mid-thought +- Simplified the Workflow tool's inline progress display — live agent counts now show only in the persistent workflow status row below the prompt +- The post-response timer now shows "Waiting for N background agents/workflows to finish" when backgrounded agents or workflows are still running, and reports the cumulative time once their results are processed +- Added the session entrypoint as an OpenTelemetry metric attribute (`app.entrypoint`, opt-in via `OTEL_METRICS_INCLUDE_ENTRYPOINT=true`) +- Fixed terminal styling degrading in very long sessions by recycling the renderer's style pool +- Fixed the sandbox-enabled warning not appearing in condensed startup mode — it now shows in every layout +- Fixed the loading spinner showing "still thinking"/"almost done thinking" while a tool is running, and reset the thinking status to "thinking" after each tool +- Fixed focus mode showing a spurious "N messages hidden" count on turns with no hidden activity +- Fixed clicking a link inside an expanded tool result collapsing the section instead of opening the link +- Fixed markdown table cell borders inheriting the color of inline code, wrapped continuation lines losing their style, and empty header cells showing a label in the narrow-terminal stacked layout +- Fixed plugin MCP servers with the same command but different environment variables being incorrectly deduplicated +- Fixed `/doctor` reporting "marketplace not found" or "plugin not found" for stale `enabledPlugins` entries referencing removed marketplaces or dropped plugins +- Fixed plugins that track a git branch silently no longer receiving updates after the plugin registry was rebuilt +- Fixed remote MCP servers failing to connect in Claude Code Remote sessions when the egress proxy is enabled +- Fixed the effort-change confirmation dialog appearing when the conversation has no messages or when switching between effort levels that resolve to the same underlying value +- Fixed the Agent tool description referencing an agent list that is never delivered when running with `--bare` or with attachments disabled +- Fixed a background worker crash in `claude agents` when accepting a stale permission prompt after a subagent was cancelled +- Fixed `cache_creation_input_tokens` reporting as 0 in transcript and result usage when the API reports cache writes only via the nested `cache_creation` breakdown +- Fixed the PushNotification tool incorrectly reporting "Mobile push not sent (Remote Control inactive)" in SDK-hosted sessions when Remote Control is enabled +- Fixed sessions getting stuck after a model or login switch left stale thinking-block signatures in history; now stripped proactively with a retry safety-net + +## 2.1.150 + +- Internal infrastructure improvements (no user-facing changes) + +## 2.1.149 + +- `/usage` now shows a per-category breakdown of what's driving your limits usage — skills, subagents, plugins, and per-MCP-server cost +- `/diff` detail view can now be scrolled with the keyboard (arrows, `j`/`k`, `PgUp`/`PgDn`, `Space`, `Home`/`End`) +- Markdown output now renders GFM task list checkboxes (`- [ ] todo` / `- [x] done`) instead of plain bullets +- Enterprise: added the `allowAllClaudeAiMcps` managed setting to load claude.ai cloud MCP connectors alongside `managed-mcp.json` +- Fixed a PowerShell permission bypass: built-in `cd` functions (`cd..`, `cd\`, `cd~`, `X:`) changed the working directory undetected, letting a later command read outside the workspace +- Fixed the sandbox write allowlist in git worktrees covering the entire main repository root instead of only the shared `.git` directory (with `hooks/` and `config` denied) +- Fixed PowerShell prefix/wildcard allow rules (e.g. `PowerShell(dotnet.exe build *)`) not pre-approving native executables and scripts +- Fixed a permission-analysis gap where the parser trusted stale variable-tracking values for `PWD`/`OLDPWD`/`DIRSTACK` across `cd`/`pushd`/`popd` +- Fixed `find` in the Bash tool exhausting the macOS system file/vnode table and crashing the host on large directory trees +- Fixed the managed-settings approval dialog leaving the terminal frozen after accepting at startup +- Fixed `/ultraplan` and remote session creation failing with "Could not capture uncommitted changes" when the working tree has no real changes +- Fixed `otelHeadersHelper` failing silently when the script path contains spaces; helper failures are now reported in `/doctor` and the debug log +- Fixed the thinking spinner staying amber across tool calls and onto fresh thinking bursts +- Fixed collapsed Bash output reporting the wrong hidden-line count for outputs with many short lines +- Fixed slash-command argument-hint clipping trailing typed characters when the hint overflows the input box +- Fixed argument-hint and progressive arg suggestions not appearing after Tab-completing a skill whose frontmatter `name:` differs from its directory basename +- Fixed the status bar showing the user's baseline `/effort` setting instead of the effort level applied by skill/agent `effort:` frontmatter +- Fixed Ctrl+O transcript view freezing at the moment it was opened instead of tailing new messages +- Fixed editing a recalled prompt-history entry losing the edit when navigating further up/down with arrow keys +- Fixed `/config` exit summary reporting phantom changes to auto-compact and theme when toggling unrelated settings +- Fixed `/insights` crashing when cached session-meta files are missing optional fields +- Fixed malformed PowerShell and History tool calls with missing input being misclassified as reads in transcript collapsing +- Fixed renaming a Remote Control session from claude.ai or the Claude mobile app not updating the local session name for `claude --resume` +- Fixed a race where a just-submitted prompt could appear twice in the up-arrow history +- Fixed tapping the "Jump to bottom" pill in fullscreen mode not dismissing it immediately +- Improved `/feedback` reports to include the conversation that happened before context compaction, making issues from earlier in long sessions easier to triage + +## 2.1.148 + +- Fixed the Bash tool returning exit code 127 on every command for some users (a regression introduced in 2.1.147) + +## 2.1.147 + +- Pinned background sessions (`Ctrl+T` in `claude agents`) now stay alive when idle, are restarted in place to apply Claude Code updates, and are shed under memory pressure only after non-pinned sessions +- Renamed `/simplify` to `/code-review`. It now reports correctness bugs at a chosen effort level (e.g., `/code-review high`); pass `--comment` to post findings as inline GitHub PR comments. The old cleanup-and-fix behavior has been removed +- Improved auto-updater: retries transient network failures, reports specific error categories and OS error codes on failure, and shows the current version when an update fails +- Improved diff rendering performance for large file edits +- Prompt history no longer records consecutive duplicate entries — recalling a prompt with arrow-up and submitting it again won't add another copy +- Fixed enterprise login restrictions (`forceLoginOrgUUID` and `forceLoginMethod` managed-settings) not being enforced against third-party-provider and API-key sessions +- Fixed `&` in `!` command output displaying as `&`, which broke copy-pasting URLs from commands like `gcloud auth login` on headless machines +- Fixed unknown slash commands silently doing nothing in headless/SDK mode — they now show an error message +- Fixed `/help` rendering a broken tab header and showing only one command per page on small terminals when not in fullscreen mode +- Fixed shell snapshot dropping user functions whose names start with a single underscore, which broke aliases referencing them +- Fixed plugin agents that declare multiple `Agent(...)` types in `tools:` frontmatter dropping all but the last entry +- Fixed hook `if` conditions like `PowerShell(git push*)` never matching — only `PowerShell(*)` worked +- Fixed PowerShell tool dropping output for commands that rely on the default formatter +- Fixed: on Windows, "Yes, and don't ask again" for a PowerShell script invocation now writes a rule that actually matches on subsequent runs +- Fixed PowerShell tool failing on Windows with exit code 1 when `pwsh` is installed via winget or the Microsoft Store +- Fixed `/effort` opening with the slider on the wrong level — it now starts at your current effort +- Fixed paginating MCP servers dropping resources, templates, and prompts past page 1 +- Fixed full-screen strobing in attached background sessions on Windows Terminal while Claude is streaming +- Fixed: on Windows, removing a background-job worktree no longer follows NTFS junctions into the main repo +- Fixed `/background` refusing sessions whose only typed input was a skill or custom slash command +- Fixed auto mode suppressing `AskUserQuestion` when the user or a skill explicitly relies on it; the auto-mode classifier now sees the user's answers as intent signal +- Fixed `/theme` "New custom theme" and color editor dialogs not responding to Esc +- Fixed an uncaught exception at the end of streaming sessions when running via the Agent SDK +- Fixed a rare hang when waiting for scroll to settle on Windows +- Fixed stale and doubled rows in the agent view list on Windows when background session results contain wide (CJK) characters +- Fixed pasted text being delivered to agents as an unreadable `[Pasted text #N]` placeholder instead of the actual content +- Fixed plugin component counts in `claude plugin details` and `/plugin` being doubled when a plugin's manifest listed paths overlapping its default directories +- Fixed backgrounded sessions re-prompting for tool permissions you already granted with "don't ask again" +- Fixed GNOME Terminal right-click and middle-click paste not inserting text +- Fixed `CLAUDE_CODE_SUBAGENT_MODEL` not applying to teammate processes spawned by agent teams +- Fixed slash commands followed by a tab or newline being treated as an unknown command +- Fixed several spacing and layout glitches in the `/plugin`, `/status`, `/mobile`, `/sandbox`, and `/permissions` menus +- Fixed stripped images prompting the model to repeatedly re-read media that was no longer present + +## 2.1.145 + +- Added `claude agents --json` to list live Claude sessions as JSON for scripting (tmux-resurrect, status bars, session pickers) +- Added `agent_id` and `parent_agent_id` attributes to `claude_code.tool` OTEL spans, and fixed trace parenting so background subagent spans nest under the dispatching Agent tool span +- Status line JSON input now includes GitHub repo and PR information when detected +- `/plugin` Discover and Browse screens now show a plugin's commands, agents, skills, hooks, and MCP/LSP servers before installation +- `claude agents` terminal tab title now shows the awaiting-input count so an alt-tabbed window tells you when an agent needs attention +- Slash command and @-mention suggestion list now supports mouse hover and click in fullscreen mode +- Stop and SubagentStop hook input now includes `background_tasks` and `session_crons` fields +- Fixed a permission-prompt bypass where bare variable assignments to non-allowlisted environment variables in Bash commands were auto-approved +- Fixed MCP prompt slash commands showing raw server validation errors when a required argument is omitted — the error now names the missing argument and shows expected usage +- Fixed the spinner and elapsed-time display freezing until a keypress after the terminal was resized or refocused +- Fixed the cross-project resume hint failing in default Windows PowerShell 5.1 — Windows now uses `;` as the command separator +- Fixed voice push-to-talk not working in the agent view's reply pane +- Fixed task lists rendering in random order when several tasks are created at once +- Fixed stale "Failed to install Anthropic marketplace" banner showing when the marketplace is already installed +- Fixed the PR badge in the footer not updating immediately after `gh pr create` and other PR-state-changing commands run in-session +- Fixed Agent Teams teammates with non-ASCII names failing every API call due to invalid header encoding +- Fixed `/review` using a deprecated `projectCards` GraphQL query that errored on repos with Classic Projects +- Fixed `claude plugin validate` not flagging `skills:` entries that point at a file instead of a directory — the error now suggests the parent directory +- Fixed an infinite loop where a skill using `context: fork` could repeatedly re-invoke itself instead of running +- Improved the Read tool to return a truncated first page with a "PARTIAL view" notice instead of a hard error when a whole-file read exceeds the token limit + +## 2.1.144 + +- Added `/resume` support for background sessions — sessions started via `claude --bg` or agent view now appear alongside interactive ones, marked with `bg` +- Added elapsed duration to background subagent completion notifications (e.g. "Agent completed · 3h 2m 5s") +- The `/plugin` browse and discover panes now show when a plugin was last updated +- `/model` now changes the model for the current session only; press `d` in the model picker to set a default for new sessions +- Renamed "extra usage" to "usage credits" across CLI copy; `/extra-usage` is now `/usage-credits` (old name still works) +- Fixed startup hanging up to 75s when `api.anthropic.com` is unreachable (captive portal, firewall, VPN issues) — side-channel API calls now time out after 15s +- Fixed garbled terminal output after a missed window-resize event (e.g. dragging a VS Code split-pane divider) — now self-heals on the next frame instead of requiring Ctrl+L +- Fixed progressive terminal display corruption (stale/garbled glyphs) that could appear in very long sessions and only cleared on terminal resize or restart +- Reduced terminal rendering glitches in VS Code by reducing spinner animation color count +- Fixed macOS background sessions crashing with "exit 1 before init" when the project lives under a Full Disk Access-protected folder (regression in 2.1.143) +- Fixed an unrecoverable conversation when reading a file whose image extension doesn't match its contents (e.g. HTML saved as .png) — now falls back to text +- Fewer spurious tool errors during search: `head`/`tail` file views now satisfy the read-before-edit check, and a "no matches" result (exit code 1) from `egrep`, `fgrep`, `git grep`, or `git diff` is no longer reported as a command failure +- Fixed `/branch` failing with "No conversation to branch" after entering a worktree or in some background sessions +- Fixed pressing Escape in the AskUserQuestion notes field aborting the turn instead of returning to answer selection +- Fixed model selection not applying when changed via the IDE model picker or `applyFlagSettings` after startup +- Resumed sessions now keep the model they were using instead of picking up another session's `/model` choice +- Fixed Bedrock and Vertex users unable to select "Opus (1M context)" from the `/model` picker (regression in v2.1.129) +- Fixed remote-session login failing with "Can't access this organization" for users with `forceLoginMethod` and `forceLoginOrgUUID` set +- Fixed MCP servers with paginated `tools/list` responses only returning the first page, silently dropping tools +- Fixed MCP images with unsupported MIME types (e.g. SVG) breaking the conversation — now saved to disk and referenced in the tool result +- Fixed file descriptor exhaustion when a build runs inside a skill directory — non-`.md` files no longer trigger skill reloads +- Fixed session title being generated from plugin monitor output instead of the user's first prompt +- Fixed Skill tool failing with permission error in headless mode (regression in v2.1.141) +- Fixed plugins enabled in your own settings showing "not cached" errors after first load on a fresh machine; plugins enabled only by a project's `.claude/settings.json` now show an actionable `claude plugin install` hint +- Fixed `claude mcp list` silently reporting no servers when `.mcp.json` can't be parsed (e.g. using VS Code's `"servers"` key instead of `"mcpServers"`) — now shows configuration errors +- Fixed background side-queries on custom `ANTHROPIC_BASE_URL` setups and Bedrock Mantle not using Haiku — now falls back correctly when a first-party API key is configured or no Haiku model is set +- Fixed scrolling in attached background sessions on Windows — PgUp/PgDn, mouse wheel, and Ctrl+O transcript navigation now work +- Fixed a crash when closing the terminal while attached to a background session +- Fixed on Windows, pressing ← in `claude agents` leaving the list unresponsive to keyboard input +- Fixed ghost characters at the left edge when switching panes in Agent View on Windows Terminal with CJK content +- `/bg` and `←`-detach now preserve directories added via `/add-dir` +- Fixed Edit/Write refusing with "background session hasn't isolated its changes yet" right after detaching a session that was already editing in place +- Fixed `claude respawn ` on a stopped background session showing "stopped" instead of running +- Fixed `/resume` picker not showing sessions forked from a background session +- Fixed opening a session from `claude agents` or running `claude logs ` hanging when the background service is unresponsive — now times out after 10s with a recovery hint +- Fixed background Bash tasks spawned by subagents staying "Running" in SDK task panels after the process exits +- Fixed completed or stopped background sessions briefly failing to wake being permanently marked as a startup crash +- Fixed markdown links in `claude agents` attached sessions rendering as plain text instead of clickable hyperlinks +- Fixed custom `spinnerVerbs` applying to the post-turn duration message — past-tense built-ins like "Worked for 5s" are restored there +- `claude agents` / `--bg` rejection messages now name the specific gate (non-TTY, env var, or setting) instead of a generic message +- `claude --bg --name