mirror of
https://github.com/anthropics/claude-code.git
synced 2026-04-16 16:07:50 +00:00
Compare commits
45 Commits
ashwin/che
...
ashwin/log
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e88b2d253 | ||
|
|
48ed55b459 | ||
|
|
40251280cc | ||
|
|
8f0379c698 | ||
|
|
10c1ec5391 | ||
|
|
6c7836e02f | ||
|
|
6f6fc43c73 | ||
|
|
944eb4eff6 | ||
|
|
21df74bb49 | ||
|
|
66ce673883 | ||
|
|
07b198b9de | ||
|
|
8ad36c459c | ||
|
|
b48dfb8e87 | ||
|
|
55219b8b4e | ||
|
|
812c27b8b3 | ||
|
|
e0d79c3571 | ||
|
|
c8207b4f68 | ||
|
|
4c056f7a09 | ||
|
|
b328530abd | ||
|
|
486b305708 | ||
|
|
8e23e7d791 | ||
|
|
68d43db2a0 | ||
|
|
9285dfbf2f | ||
|
|
90c26533d1 | ||
|
|
d45bce242d | ||
|
|
f91aed5440 | ||
|
|
54a4ed0f5e | ||
|
|
33e37bd828 | ||
|
|
ff15c6f147 | ||
|
|
0cbe1dcac5 | ||
|
|
a705bca81c | ||
|
|
ecaf0d818a | ||
|
|
397442ddf5 | ||
|
|
5def9264e5 | ||
|
|
0149827a77 | ||
|
|
c93c724eeb | ||
|
|
545d78c331 | ||
|
|
e16c9857ef | ||
|
|
a39ae004aa | ||
|
|
74ba615503 | ||
|
|
3d2166eec9 | ||
|
|
beacb95320 | ||
|
|
46ca39c463 | ||
|
|
a6091b65c0 | ||
|
|
11cfc055af |
@@ -3,8 +3,11 @@ FROM node:20
|
||||
ARG TZ
|
||||
ENV TZ="$TZ"
|
||||
|
||||
ARG CLAUDE_CODE_VERSION=latest
|
||||
|
||||
# Install basic development tools and iptables/ipset
|
||||
RUN apt update && apt install -y less \
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
less \
|
||||
git \
|
||||
procps \
|
||||
sudo \
|
||||
@@ -19,7 +22,10 @@ RUN apt update && apt install -y less \
|
||||
iproute2 \
|
||||
dnsutils \
|
||||
aggregate \
|
||||
jq
|
||||
jq \
|
||||
nano \
|
||||
vim \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Ensure default node user has access to /usr/local/share
|
||||
RUN mkdir -p /usr/local/share/npm-global && \
|
||||
@@ -42,10 +48,11 @@ RUN mkdir -p /workspace /home/node/.claude && \
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
ARG GIT_DELTA_VERSION=0.18.2
|
||||
RUN ARCH=$(dpkg --print-architecture) && \
|
||||
wget "https://github.com/dandavison/delta/releases/download/0.18.2/git-delta_0.18.2_${ARCH}.deb" && \
|
||||
sudo dpkg -i "git-delta_0.18.2_${ARCH}.deb" && \
|
||||
rm "git-delta_0.18.2_${ARCH}.deb"
|
||||
wget "https://github.com/dandavison/delta/releases/download/${GIT_DELTA_VERSION}/git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \
|
||||
sudo dpkg -i "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \
|
||||
rm "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb"
|
||||
|
||||
# Set up non-root user
|
||||
USER node
|
||||
@@ -57,8 +64,13 @@ ENV PATH=$PATH:/usr/local/share/npm-global/bin
|
||||
# Set the default shell to zsh rather than sh
|
||||
ENV SHELL=/bin/zsh
|
||||
|
||||
# Set the default editor and visual
|
||||
ENV EDITOR nano
|
||||
ENV VISUAL nano
|
||||
|
||||
# Default powerline10k theme
|
||||
RUN sh -c "$(wget -O- https://github.com/deluan/zsh-in-docker/releases/download/v1.2.0/zsh-in-docker.sh)" -- \
|
||||
ARG ZSH_IN_DOCKER_VERSION=1.2.0
|
||||
RUN sh -c "$(wget -O- https://github.com/deluan/zsh-in-docker/releases/download/v${ZSH_IN_DOCKER_VERSION}/zsh-in-docker.sh)" -- \
|
||||
-p git \
|
||||
-p fzf \
|
||||
-a "source /usr/share/doc/fzf/examples/key-bindings.zsh" \
|
||||
@@ -67,7 +79,8 @@ RUN sh -c "$(wget -O- https://github.com/deluan/zsh-in-docker/releases/download/
|
||||
-x
|
||||
|
||||
# Install Claude
|
||||
RUN npm install -g @anthropic-ai/claude-code
|
||||
RUN npm install -g @anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}
|
||||
|
||||
|
||||
# Copy and set up firewall script
|
||||
COPY init-firewall.sh /usr/local/bin/
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
"args": {
|
||||
"TZ": "${localEnv:TZ:America/Los_Angeles}"
|
||||
"TZ": "${localEnv:TZ:America/Los_Angeles}",
|
||||
"CLAUDE_CODE_VERSION": "latest",
|
||||
"GIT_DELTA_VERSION": "0.18.2",
|
||||
"ZSH_IN_DOCKER_VERSION": "1.2.0"
|
||||
}
|
||||
},
|
||||
"runArgs": [
|
||||
@@ -38,10 +41,10 @@
|
||||
},
|
||||
"remoteUser": "node",
|
||||
"mounts": [
|
||||
"source=claude-code-bashhistory,target=/commandhistory,type=volume",
|
||||
"source=claude-code-config,target=/home/node/.claude,type=volume"
|
||||
"source=claude-code-bashhistory-${devcontainerId},target=/commandhistory,type=volume",
|
||||
"source=claude-code-config-${devcontainerId},target=/home/node/.claude,type=volume"
|
||||
],
|
||||
"remoteEnv": {
|
||||
"containerEnv": {
|
||||
"NODE_OPTIONS": "--max-old-space-size=4096",
|
||||
"CLAUDE_CONFIG_DIR": "/home/node/.claude",
|
||||
"POWERLEVEL9K_DISABLE_GITSTATUS": "true"
|
||||
|
||||
3
.github/workflows/claude-issue-triage.yml
vendored
3
.github/workflows/claude-issue-triage.yml
vendored
@@ -13,6 +13,9 @@ jobs:
|
||||
issues: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Create triage prompt
|
||||
run: |
|
||||
mkdir -p /tmp/claude-prompts
|
||||
|
||||
28
.github/workflows/lock-closed-issues.yml
vendored
Normal file
28
.github/workflows/lock-closed-issues.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: "Lock Stale Issues"
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# 8am Pacific = 1pm UTC (2pm UTC during DST)
|
||||
- cron: "0 14 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
concurrency:
|
||||
group: lock-threads
|
||||
|
||||
jobs:
|
||||
lock-threads:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5.0.1
|
||||
with:
|
||||
issue-inactive-days: "7"
|
||||
process-only: "issues"
|
||||
log-output: true
|
||||
issue-comment: >
|
||||
This issue has been automatically locked since it was
|
||||
closed and has not had any activity for 7 days.
|
||||
If you're experiencing a similar issue, please file a new issue
|
||||
and reference this one if it's relevant.
|
||||
139
CHANGELOG.md
139
CHANGELOG.md
@@ -1,8 +1,143 @@
|
||||
# Changelog
|
||||
|
||||
## 1.0.62
|
||||
|
||||
- Added @-mention support with typeahead for custom agents. @<your-custom-agent> to invoke it
|
||||
- Hooks: Added SessionStart hook for new session initialization
|
||||
- /add-dir command now supports typeahead for directory paths
|
||||
- Improved network connectivity check reliability
|
||||
|
||||
## 1.0.61
|
||||
|
||||
- Transcript mode (Ctrl+R): Changed Esc to exit transcript mode rather than interrupt
|
||||
- Settings: Added `--settings` flag to load settings from a JSON file
|
||||
- Settings: Fixed resolution of settings files paths that are symlinks
|
||||
- OTEL: Fixed reporting of wrong organization after authentication changes
|
||||
- Slash commands: Fixed permissions checking for allowed-tools with Bash
|
||||
- IDE: Added support for pasting images in VSCode MacOS using ⌘+V
|
||||
- IDE: Added `CLAUDE_CODE_AUTO_CONNECT_IDE=false` for disabling IDE auto-connection
|
||||
- Added `CLAUDE_CODE_SHELL_PREFIX` for wrapping Claude and user-provided shell commands run by Claude Code
|
||||
|
||||
## 1.0.60
|
||||
|
||||
- You can now create custom subagents for specialized tasks! Run /agents to get started
|
||||
|
||||
## 1.0.59
|
||||
|
||||
- SDK: Added tool confirmation support with canUseTool callback
|
||||
- SDK: Allow specifying env for spawned process
|
||||
- Hooks: Exposed PermissionDecision to hooks (including "ask")
|
||||
- Hooks: UserPromptSubmit now supports additionalContext in advanced JSON output
|
||||
- Fixed issue where some Max users that specified Opus would still see fallback to Sonnet
|
||||
|
||||
## 1.0.58
|
||||
|
||||
- Added support for reading PDFs
|
||||
- MCP: Improved server health status display in 'claude mcp list'
|
||||
- Hooks: Added CLAUDE_PROJECT_DIR env var for hook commands
|
||||
|
||||
## 1.0.57
|
||||
|
||||
- Added support for specifying a model in slash commands
|
||||
- Improved permission messages to help Claude understand allowed tools
|
||||
- Fix: Remove trailing newlines from bash output in terminal wrapping
|
||||
|
||||
## 1.0.56
|
||||
|
||||
- Windows: Enabled shift+tab for mode switching on versions of Node.js that support terminal VT mode
|
||||
- Fixes for WSL IDE detection
|
||||
- Fix an issue causing awsRefreshHelper changes to .aws directory not to be picked up
|
||||
|
||||
## 1.0.55
|
||||
|
||||
- Clarified knowledge cutoff for Opus 4 and Sonnet 4 models
|
||||
- Windows: fixed Ctrl+Z crash
|
||||
- SDK: Added ability to capture error logging
|
||||
- Add --system-prompt-file option to override system prompt in print mode
|
||||
|
||||
## 1.0.54
|
||||
|
||||
- Hooks: Added UserPromptSubmit hook and the current working directory to hook inputs
|
||||
- Custom slash commands: Added argument-hint to frontmatter
|
||||
- Windows: OAuth uses port 45454 and properly constructs browser URL
|
||||
- Windows: mode switching now uses alt + m, and plan mode renders properly
|
||||
- Shell: Switch to in-memory shell snapshot to fix file-related errors
|
||||
|
||||
## 1.0.53
|
||||
|
||||
- Updated @-mention file truncation from 100 lines to 2000 lines
|
||||
- Add helper script settings for AWS token refresh: awsAuthRefresh (for foreground operations like aws sso login) and awsCredentialExport (for background operation with STS-like response).
|
||||
|
||||
## 1.0.52
|
||||
|
||||
- Added support for MCP server instructions
|
||||
|
||||
## 1.0.51
|
||||
|
||||
- Added support for native Windows (requires Git for Windows)
|
||||
- Added support for Bedrock API keys through environment variable AWS_BEARER_TOKEN_BEDROCK
|
||||
- Settings: /doctor can now help you identify and fix invalid setting files
|
||||
- `--append-system-prompt` can now be used in interactive mode, not just --print/-p.
|
||||
- Increased auto-compact warning threshold from 60% to 80%
|
||||
- Fixed an issue with handling user directories with spaces for shell snapshots
|
||||
- OTEL resource now includes os.type, os.version, host.arch, and wsl.version (if running on Windows Subsystem for Linux)
|
||||
- Custom slash commands: Fixed user-level commands in subdirectories
|
||||
- Plan mode: Fixed issue where rejected plan from sub-task would get discarded
|
||||
|
||||
## 1.0.48
|
||||
|
||||
- Fixed a bug in v1.0.45 where the app would sometimes freeze on launch
|
||||
- Added progress messages to Bash tool based on the last 5 lines of command output
|
||||
- Added expanding variables support for MCP server configuration
|
||||
- Moved shell snapshots from /tmp to ~/.claude for more reliable Bash tool calls
|
||||
- Improved IDE extension path handling when Claude Code runs in WSL
|
||||
- Hooks: Added a PreCompact hook
|
||||
- Vim mode: Added c, f/F, t/T
|
||||
|
||||
## 1.0.45
|
||||
|
||||
- Redesigned Search (Grep) tool with new tool input parameters and features
|
||||
- Disabled IDE diffs for notebook files, fixing "Timeout waiting after 1000ms" error
|
||||
- Fixed config file corruption issue by enforcing atomic writes
|
||||
- Updated prompt input undo to Ctrl+\_ to avoid breaking existing Ctrl+U behavior, matching zsh's undo shortcut
|
||||
- Stop Hooks: Fixed transcript path after /clear and fixed triggering when loop ends with tool call
|
||||
- Custom slash commands: Restored namespacing in command names based on subdirectories. For example, .claude/commands/frontend/component.md is now /frontend:component, not /component.
|
||||
|
||||
## 1.0.44
|
||||
|
||||
- New /export command lets you quickly export a conversation for sharing
|
||||
- MCP: resource_link tool results are now supported
|
||||
- MCP: tool annotations and tool titles now display in /mcp view
|
||||
- Changed Ctrl+Z to suspend Claude Code. Resume by running `fg`. Prompt input undo is now Ctrl+U.
|
||||
|
||||
## 1.0.43
|
||||
|
||||
- Fixed a bug where the theme selector was saving excessively
|
||||
- Hooks: Added EPIPE system error handling
|
||||
|
||||
## 1.0.42
|
||||
|
||||
- Added tilde (`~`) expansion support to `/add-dir` command
|
||||
|
||||
## 1.0.41
|
||||
|
||||
- Hooks: Split Stop hook triggering into Stop and SubagentStop
|
||||
- Hooks: Enabled optional timeout configuration for each command
|
||||
- Hooks: Added "hook_event_name" to hook input
|
||||
- Fixed a bug where MCP tools would display twice in tool list
|
||||
- New tool parameters JSON for Bash tool in `tool_decision` event
|
||||
|
||||
## 1.0.40
|
||||
|
||||
- Fixed a bug causing API connection errors with UNABLE_TO_GET_ISSUER_CERT_LOCALLY if `NODE_EXTRA_CA_CERTS` was set
|
||||
|
||||
## 1.0.39
|
||||
|
||||
- New Active Time metric in OpenTelemetry logging
|
||||
|
||||
## 1.0.38
|
||||
|
||||
- Released [hooks](https://docs.anthropic.com/en/docs/claude-code/hooks). Special thanks to community input in [Github Issues](https://github.com/anthropics/claude-code/issues/712)
|
||||
- Released hooks. Special thanks to community input in https://github.com/anthropics/claude-code/issues/712. Docs: https://docs.anthropic.com/en/docs/claude-code/hooks
|
||||
|
||||
## 1.0.37
|
||||
|
||||
@@ -24,7 +159,7 @@
|
||||
## 1.0.33
|
||||
|
||||
- Improved logging functionality with session ID support
|
||||
- Added undo functionality (Ctrl+Z and vim 'u' command)
|
||||
- Added prompt input undo functionality (Ctrl+Z and vim 'u' command)
|
||||
- Improvements to plan mode
|
||||
|
||||
## 1.0.32
|
||||
|
||||
148
Script/run_devcontainer_claude_code.ps1
Normal file
148
Script/run_devcontainer_claude_code.ps1
Normal file
@@ -0,0 +1,148 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Automates the setup and connection to a DevContainer environment using either Docker or Podman on Windows.
|
||||
|
||||
.DESCRIPTION
|
||||
This script automates the process of initializing, starting, and connecting to a DevContainer
|
||||
using either Docker or Podman as the container backend. It must be executed from the root
|
||||
directory of your project and assumes the script is located in a 'Script' subdirectory.
|
||||
|
||||
.PARAMETER Backend
|
||||
Specifies the container backend to use. Valid values are 'docker' or 'podman'.
|
||||
|
||||
.EXAMPLE
|
||||
.\Script\run_devcontainer_claude_code.ps1 -Backend docker
|
||||
Uses Docker as the container backend.
|
||||
|
||||
.EXAMPLE
|
||||
.\Script\run_devcontainer_claude_code.ps1 -Backend podman
|
||||
Uses Podman as the container backend.
|
||||
|
||||
.NOTES
|
||||
Project Structure:
|
||||
Project/
|
||||
├── .devcontainer/
|
||||
└── Script/
|
||||
└── run_devcontainer_claude_code.ps1
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[ValidateSet('docker','podman')]
|
||||
[string]$Backend
|
||||
)
|
||||
|
||||
# Notify script start
|
||||
Write-Host "--- DevContainer Startup & Connection Script ---"
|
||||
Write-Host "Using backend: $($Backend)"
|
||||
|
||||
# --- Prerequisite Check ---
|
||||
Write-Host "Checking for required commands..."
|
||||
try {
|
||||
Get-Command $Backend -ErrorAction Stop | Out-Null
|
||||
Write-Host "- $($Backend) command found."
|
||||
Get-Command devcontainer -ErrorAction Stop | Out-Null
|
||||
Write-Host "- devcontainer command found."
|
||||
}
|
||||
catch {
|
||||
Write-Error "A required command is not installed or not in your PATH."
|
||||
Write-Error "Please ensure '$($_.Exception.Message.Split(':')[0])' and 'devcontainer' are installed and accessible."
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
# --- Backend-Specific Initialization ---
|
||||
if ($Backend -eq 'podman') {
|
||||
Write-Host "--- Podman Backend Initialization ---"
|
||||
|
||||
# --- Step 1a: Initialize Podman machine ---
|
||||
Write-Host "Initializing Podman machine 'claudeVM'..."
|
||||
try {
|
||||
& podman machine init claudeVM
|
||||
Write-Host "Podman machine 'claudeVM' initialized or already exists."
|
||||
} catch {
|
||||
Write-Error "Failed to initialize Podman machine: $($_.Exception.Message)"
|
||||
exit 1 # Exit script on error
|
||||
}
|
||||
|
||||
# --- Step 1b: Start Podman machine ---
|
||||
Write-Host "Starting Podman machine 'claudeVM'..."
|
||||
try {
|
||||
& podman machine start claudeVM -q
|
||||
Write-Host "Podman machine started or already running."
|
||||
} catch {
|
||||
Write-Error "Failed to start Podman machine: $($_.Exception.Message)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- Step 2: Set default connection ---
|
||||
Write-Host "Setting default Podman connection to 'claudeVM'..."
|
||||
try {
|
||||
& podman system connection default claudeVM
|
||||
Write-Host "Default connection set."
|
||||
} catch {
|
||||
Write-Warning "Failed to set default Podman connection (may be already set or machine issue): $($_.Exception.Message)"
|
||||
}
|
||||
|
||||
} elseif ($Backend -eq 'docker') {
|
||||
Write-Host "--- Docker Backend Initialization ---"
|
||||
|
||||
# --- Step 1 & 2: Check Docker Desktop ---
|
||||
Write-Host "Checking if Docker Desktop is running and docker command is available..."
|
||||
try {
|
||||
docker info | Out-Null
|
||||
Write-Host "Docker Desktop (daemon) is running."
|
||||
} catch {
|
||||
Write-Error "Docker Desktop is not running or docker command not found."
|
||||
Write-Error "Please ensure Docker Desktop is running."
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# --- Step 3: Bring up DevContainer ---
|
||||
Write-Host "Bringing up DevContainer in the current folder..."
|
||||
try {
|
||||
$arguments = @('up', '--workspace-folder', '.')
|
||||
if ($Backend -eq 'podman') {
|
||||
$arguments += '--docker-path', 'podman'
|
||||
}
|
||||
& devcontainer @arguments
|
||||
Write-Host "DevContainer startup process completed."
|
||||
} catch {
|
||||
Write-Error "Failed to bring up DevContainer: $($_.Exception.Message)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- Step 4: Get DevContainer ID ---
|
||||
Write-Host "Finding the DevContainer ID..."
|
||||
$currentFolder = (Get-Location).Path
|
||||
|
||||
try {
|
||||
$containerId = (& $Backend ps --filter "label=devcontainer.local_folder=$currentFolder" --format '{{.ID}}').Trim()
|
||||
} catch {
|
||||
$displayCommand = "$Backend ps --filter `"label=devcontainer.local_folder=$currentFolder`" --format '{{.ID}}'"
|
||||
Write-Error "Failed to get container ID (Command: $displayCommand): $($_.Exception.Message)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (-not $containerId) {
|
||||
Write-Error "Could not find DevContainer ID for the current folder ('$currentFolder')."
|
||||
Write-Error "Please check if 'devcontainer up' was successful and the container is running."
|
||||
exit 1
|
||||
}
|
||||
Write-Host "Found container ID: $containerId"
|
||||
|
||||
# --- Step 5 & 6: Execute command and enter interactive shell inside container ---
|
||||
Write-Host "Executing 'claude' command and then starting zsh session inside container $($containerId)..."
|
||||
try {
|
||||
& $Backend exec -it $containerId zsh -c 'claude; exec zsh'
|
||||
Write-Host "Interactive session ended."
|
||||
} catch {
|
||||
$displayCommand = "$Backend exec -it $containerId zsh -c 'claude; exec zsh'"
|
||||
Write-Error "Failed to execute command inside container (Command: $displayCommand): $($_.Exception.Message)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Notify script completion
|
||||
Write-Host "--- Script completed ---"
|
||||
83
examples/hooks/bash_command_validator_example.py
Normal file
83
examples/hooks/bash_command_validator_example.py
Normal file
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Claude Code Hook: Bash Command Validator
|
||||
=========================================
|
||||
This hook runs as a PreToolUse hook for the Bash tool.
|
||||
It validates bash commands against a set of rules before execution.
|
||||
In this case it changes grep calls to using rg.
|
||||
|
||||
Read more about hooks here: https://docs.anthropic.com/en/docs/claude-code/hooks
|
||||
|
||||
Make sure to change your path to your actual script.
|
||||
|
||||
{
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "python3 /path/to/claude-code/examples/hooks/bash_command_validator_example.py"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
|
||||
# Define validation rules as a list of (regex pattern, message) tuples
|
||||
_VALIDATION_RULES = [
|
||||
(
|
||||
r"^grep\b(?!.*\|)",
|
||||
"Use 'rg' (ripgrep) instead of 'grep' for better performance and features",
|
||||
),
|
||||
(
|
||||
r"^find\s+\S+\s+-name\b",
|
||||
"Use 'rg --files | rg pattern' or 'rg --files -g pattern' instead of 'find -name' for better performance",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def _validate_command(command: str) -> list[str]:
|
||||
issues = []
|
||||
for pattern, message in _VALIDATION_RULES:
|
||||
if re.search(pattern, command):
|
||||
issues.append(message)
|
||||
return issues
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
input_data = json.load(sys.stdin)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
|
||||
# Exit code 1 shows stderr to the user but not to Claude
|
||||
sys.exit(1)
|
||||
|
||||
tool_name = input_data.get("tool_name", "")
|
||||
if tool_name != "Bash":
|
||||
sys.exit(0)
|
||||
|
||||
tool_input = input_data.get("tool_input", {})
|
||||
command = tool_input.get("command", "")
|
||||
|
||||
if not command:
|
||||
sys.exit(0)
|
||||
|
||||
issues = _validate_command(command)
|
||||
if issues:
|
||||
for message in issues:
|
||||
print(f"• {message}", file=sys.stderr)
|
||||
# Exit code 2 blocks tool call and shows stderr to Claude
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user