diff --git a/.gitignore b/.gitignore index fd0faaa..2176da0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +.idea/ +.claude/ .DS_Store .venv/ __pycache__/ diff --git a/agents/optimizer.md b/agents/optimizer.md index 60aea6c..6035651 100644 --- a/agents/optimizer.md +++ b/agents/optimizer.md @@ -58,9 +58,7 @@ description: | model: inherit -maxTurns: 15 color: cyan -tools: Read, Glob, Grep, Bash, Write, Edit, Task --- You are a thin-wrapper agent that runs the codeflash CLI to optimize Python, Java, and JavaScript/TypeScript code. @@ -69,23 +67,37 @@ You are a thin-wrapper agent that runs the codeflash CLI to optimize Python, Jav Follow these steps in order: -### 0. Check API Key +### Quick Check (Fast Path) -Before anything else, check if a Codeflash API key is available: +Before running the full setup steps, run the preflight script. Use `${CLAUDE_PLUGIN_ROOT}` to locate the plugin directory: ```bash -[ -n "${CODEFLASH_API_KEY:-}" ] && [[ "${CODEFLASH_API_KEY}" == cf-* ]] && printf 'env:ok\n' || printf 'env:missing\n'; grep -l 'CODEFLASH_API_KEY.*cf-' ~/.zshrc ~/.bashrc ~/.profile ~/.kshrc ~/.cshrc ~/codeflash_env.ps1 ~/codeflash_env.bat 2>/dev/null || true +bash "${CLAUDE_PLUGIN_ROOT}/scripts/preflight.sh" ``` -If the output contains `env:ok`, proceed to Step 1. +Where `` is the target project directory from the user's prompt (or the current working directory if not specified). + +**Evaluate the output and skip ahead if everything is ready:** + +- **API key**: `api_key=ok` means the key is set. If `missing`, go to Step 0. +- **Environment**: For Python, `venv` must not be `none` and `codeflash_path` must show a path. For JS/TS, `npx_codeflash` must show a version. For Java, `codeflash_path` must show a path. If any are missing, go to Step 2. +- **Configuration**: `python_configured=yes`, `java_configured=yes`, or `jsts_configured=yes` means config exists. If missing for the relevant project type, go to Step 3. + +**If api_key=ok AND the relevant environment check passes AND config is present → skip directly to Step 4.** + +Otherwise, jump to the first failing step below. -If the output contains `env:missing` but a shell RC file path was listed, source that file to load the key: +### 0. Check API Key + +Before anything else, check if a Codeflash API key is available. Use the preflight output from the Quick Check — if `api_key=ok` was printed, the key is set, proceed to Step 1. + +If the API key is missing, try sourcing the shell RC file and re-running the preflight: ```bash -source ~/.zshrc # or whichever file had the key +bash -c "source ~/.zshrc 2>/dev/null; bash ${CLAUDE_PLUGIN_ROOT}/scripts/preflight.sh " ``` -Then proceed to Step 1. +If the key is now set, proceed to Step 1. If **no API key is found anywhere**, run the OAuth login script: @@ -139,21 +151,18 @@ The verification process depends on the project type determined in Step 1. #### 2a. Python projects -First, check that a Python virtual environment is active by running `echo $VIRTUAL_ENV`. +First, check the preflight output for `venv=`. If it shows a path (not `none`), a virtual environment is already active — proceed to checking codeflash installation below. -If `$VIRTUAL_ENV` is empty or unset, **try to find and activate a virtual environment automatically**. Look for common venv directories in the project directory (from Step 1), then in the git repo root: +If `venv=none`, **try to find a virtual environment automatically** using the Glob tool. Search for `bin/activate` files in the project directory and git repo root: -```bash -# Check these directories in order, using the project directory first: -for candidate in /.venv /venv /.venv /venv; do - if [ -f "$candidate/bin/activate" ]; then - source "$candidate/bin/activate" - break - fi -done -``` +- `/.venv/bin/activate` +- `/venv/bin/activate` +- `/.venv/bin/activate` +- `/venv/bin/activate` -After attempting auto-discovery, check `echo $VIRTUAL_ENV` again. If it is **still** empty or unset, **stop and inform the user**: +If found, record the venv path (the directory two levels up from `bin/activate`). You do NOT need to "activate" it — instead, use the full path to the codeflash binary: `/bin/codeflash`. + +If no virtual environment is found anywhere, **stop and inform the user**: > No Python virtual environment was found. Codeflash must be installed in a virtual environment. > Please create and activate one, then install codeflash: @@ -164,15 +173,15 @@ After attempting auto-discovery, check `echo $VIRTUAL_ENV` again. If it is **sti > ``` > Then restart Claude Code from within the activated virtual environment. -If a virtual environment is now active, run `$VIRTUAL_ENV/bin/codeflash --version`. If it succeeds, proceed to Step 3. +Once you have a venv path (either from `$VIRTUAL_ENV` or from Glob discovery), run `/bin/codeflash --version`. If it succeeds, proceed to Step 3. -If it fails (exit code non-zero or command not found), codeflash is not installed in the active virtual environment. Ask the user whether they'd like to install it now: +If it fails (exit code non-zero or command not found), codeflash is not installed in the virtual environment. Ask the user whether they'd like to install it now: ```bash -pip install codeflash +/bin/pip install codeflash ``` -If the user agrees, run the installation command in the project directory. If installation succeeds, proceed to Step 3. If the user declines or installation fails, stop. +If the user agrees, run the installation command. If installation succeeds, proceed to Step 3. If the user declines or installation fails, stop. #### 2b. JS/TS projects @@ -301,22 +310,24 @@ If no file and no `--all` flag, run codeflash without `--file` or `--all` to let **Always `cd` to the project directory** (from Step 1) before running codeflash, so that relative paths in the config resolve correctly. -Execute the appropriate command **in the background** (`run_in_background: true`) with a **10-minute timeout** (`timeout: 600000`): +Execute the appropriate command with a **10-minute timeout**. You MUST pass `timeout: 600000` to every Bash tool call that runs codeflash. The default 2-minute Bash timeout is too short — codeflash optimization can take several minutes. Do NOT use `run_in_background: true` — the agent must wait for the command to complete so results are captured before the agent exits. #### Python projects +Use the `run-codeflash.sh` wrapper script to cd into the project directory and run codeflash. This ensures the command is a single invocation (no `&&` chains) and matches the `Bash(*codeflash*)` permission pattern. + ```bash # Default: let codeflash detect changed files -source $VIRTUAL_ENV/bin/activate && cd && codeflash --subagent [flags] +bash "${CLAUDE_PLUGIN_ROOT}/scripts/run-codeflash.sh" /bin/codeflash --subagent [flags] # Specific file -source $VIRTUAL_ENV/bin/activate && cd && codeflash --subagent --file [--function ] [flags] +bash "${CLAUDE_PLUGIN_ROOT}/scripts/run-codeflash.sh" /bin/codeflash --subagent --file [--function ] [flags] # All files (only when explicitly requested with --all) -source $VIRTUAL_ENV/bin/activate && cd && codeflash --subagent --all [flags] +bash "${CLAUDE_PLUGIN_ROOT}/scripts/run-codeflash.sh" /bin/codeflash --subagent --all [flags] ``` -If CWD is already the project directory, omit the `cd`. Always include the `source $VIRTUAL_ENV/bin/activate` prefix to ensure the virtual environment is active in the shell that runs codeflash. +Where `` is the virtual environment path from Step 2 (either `$VIRTUAL_ENV` if set, or the path discovered via Glob like `/path/to/project/.venv`). #### JS/TS projects @@ -324,44 +335,40 @@ If CWD is already the project directory, omit the `cd`. Always include the `sour ```bash # Default: let codeflash detect changed files -cd && npx codeflash --subagent [flags] +bash "${CLAUDE_PLUGIN_ROOT}/scripts/run-codeflash.sh" npx codeflash --subagent [flags] # Specific file -cd && npx codeflash --subagent --file [--function ] [flags] +bash "${CLAUDE_PLUGIN_ROOT}/scripts/run-codeflash.sh" npx codeflash --subagent --file [--function ] [flags] # All files (only when explicitly requested with --all) -cd && npx codeflash --subagent --all [flags] +bash "${CLAUDE_PLUGIN_ROOT}/scripts/run-codeflash.sh" npx codeflash --subagent --all [flags] ``` -If CWD is already the project directory, omit the `cd`. Use `npx codeflash` (no virtual environment activation needed). - #### Java projects **Important**: Codeflash must be run from the project root (the directory containing `codeflash.toml` or `pom.xml`/`build.gradle`). ```bash # Default: let codeflash detect changed files -cd && --subagent [flags] +bash "${CLAUDE_PLUGIN_ROOT}/scripts/run-codeflash.sh" --subagent [flags] # Specific file -cd && --subagent --file [--function ] [flags] +bash "${CLAUDE_PLUGIN_ROOT}/scripts/run-codeflash.sh" --subagent --file [--function ] [flags] # All files (only when explicitly requested with --all) -cd && --subagent --all [flags] +bash "${CLAUDE_PLUGIN_ROOT}/scripts/run-codeflash.sh" --subagent --all [flags] ``` -If CWD is already the project directory, omit the `cd`. Use the binary found in Step 2c (`codeflash` or `uv run codeflash`). - -**IMPORTANT**: Always use `run_in_background: true` when calling the Bash tool to execute codeflash. This allows optimization to run in the background while Claude continues other work. Tell the user "Codeflash is optimizing in the background, you'll be notified when it completes" and do not wait for the result. +Use the binary found in Step 2c (`codeflash` or `uv run codeflash`). -### 6. Report Initial Status +**IMPORTANT**: Do NOT use `run_in_background: true` for the codeflash Bash call. Run codeflash in the **foreground** with `timeout: 600000` so the agent waits for it to complete. Background execution is handled at a higher level — this agent already runs in a forked context (`context: fork`), so the user's session is not blocked. If you use `run_in_background: true` inside the agent, the background task will be killed when the agent exits. -After starting the codeflash command in the background, immediately tell the user: -1. That codeflash is optimizing in the background -2. Which files/functions are being analyzed (if specified) -3. That they'll be notified when optimization completes +### 6. Report Results -Do not wait for the background task to finish. The user will be notified automatically when the task completes with the results (optimizations found, performance improvements, PR creation status). +After codeflash completes, report: +1. Whether optimizations were found and what performance improvements were achieved +2. Which files/functions were analyzed +3. Any errors or issues encountered ## What This Agent Does NOT Do @@ -378,3 +385,14 @@ Do not wait for the background task to finish. The user will be notified automat - **Not configured**: Interactively ask the user for module root and tests folder, then write the config (Python/JS/TS), or run `codeflash init --yes` (Java) - **No optimizations found**: Normal — not all code can be optimized, report this clearly - **"Attempting to repair broken tests..."**: Normal codeflash behavior, not an error + +## Return Format + +You run as a subagent. Your final output is returned to the main conversation context. Keep it concise to avoid polluting the main context window. + +Return ONLY a short summary: +- **Files/functions analyzed**: list them briefly +- **Result**: optimizations found (with speedups) or "no optimizations found" +- **Errors**: any issues encountered, or "none" + +Do NOT include raw command output, logs, full file contents, or step-by-step narration of what you did. diff --git a/commands/setup.md b/commands/setup.md deleted file mode 100644 index 5ab728a..0000000 --- a/commands/setup.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -description: "Set up codeflash permissions so optimization runs automatically without prompting" -argument-hint: "" -allowed-tools: Bash, Read, Write, Edit, Task, Grep, Glob, Bash(*codeflash*), Bash(git *) ---- - -Help the user configure their project so that `codeflash --subagent` runs automatically without permission prompts. - -## Steps - -1. Check if `.claude/settings.json` exists in the project root (use `git rev-parse --show-toplevel` to find it). - -2. If the file exists, read it and check if `Bash(*codeflash*)` is already in `permissions.allow`. - -3. If already configured, tell the user: "Codeflash is already configured to run automatically. No changes needed." - -4. If not configured, add `Bash(*codeflash*)` to the `permissions.allow` array in `.claude/settings.json`. Create the file and any necessary parent directories if they don't exist. Preserve any existing settings. - -5. Confirm to the user what was added and explain: "Codeflash will now run automatically in the background after commits that change code files, without prompting for permission each time." diff --git a/hooks/hooks.json b/hooks/hooks.json deleted file mode 100644 index 3f65f22..0000000 --- a/hooks/hooks.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "hooks": { - "Stop": [ - { - "matcher": "*", - "hooks": [ - { - "type": "command", - "command": "${CLAUDE_PLUGIN_ROOT}/scripts/suggest-optimize.sh", - "timeout": 30 - } - ] - } - ] - } -} diff --git a/scripts/find-venv.sh b/scripts/find-venv.sh deleted file mode 100755 index ade9ea0..0000000 --- a/scripts/find-venv.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -# Shared helper: find and activate a Python virtual environment. -# -# Requires: REPO_ROOT and CHECK_DIR to be set before sourcing. -# Effect: If no venv is active, searches common locations relative to -# CHECK_DIR and REPO_ROOT, and activates the first one found. -# After return, VIRTUAL_ENV will be set if a venv was found. -# -# Note: This helper is only used for Python projects. JS/TS projects -# do not require a virtual environment — they use npx/npm instead. - -if [ -z "${VIRTUAL_ENV:-}" ]; then - for candidate in "$CHECK_DIR/.venv" "$CHECK_DIR/venv" "$REPO_ROOT/.venv" "$REPO_ROOT/venv"; do - if [ -f "$candidate/bin/activate" ]; then - # shellcheck disable=SC1091 - source "$candidate/bin/activate" - break - fi - done -fi diff --git a/scripts/preflight.sh b/scripts/preflight.sh new file mode 100755 index 0000000..d5eee45 --- /dev/null +++ b/scripts/preflight.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# Codeflash preflight check — verifies API key, venv, and project configuration. +# Usage: bash preflight.sh +set -euo pipefail + +project_dir="${1:-.}" + +echo "=== codeflash preflight ===" + +# API key +printf "api_key=" +if [ -n "${CODEFLASH_API_KEY:-}" ] && [[ "${CODEFLASH_API_KEY}" == cf-* ]]; then + echo "ok" +else + echo "missing" +fi + +# Virtual environment +printf "venv=" +echo "${VIRTUAL_ENV:-none}" + +# Git root +git_root=$(git -C "$project_dir" rev-parse --show-toplevel 2>/dev/null || true) +echo "git_root=${git_root:-unknown}" + +# Codeflash binary +printf "codeflash_path=" +command -v codeflash 2>/dev/null || echo "not_found" + +# npx codeflash (JS/TS) +printf "npx_codeflash=" +npx codeflash --version 2>/dev/null || echo "not_found" + +# Config files +if [ -n "$git_root" ]; then + for f in codeflash.toml pyproject.toml package.json; do + [ -f "$git_root/$f" ] && echo "found=$f" + done + grep -q '\[tool\.codeflash\]' "$git_root/pyproject.toml" 2>/dev/null && echo "python_configured=yes" || true + grep -q '\[tool\.codeflash\]' "$git_root/codeflash.toml" 2>/dev/null && echo "java_configured=yes" || true + python3 -c "import json,sys; d=json.load(open(sys.argv[1])); print('jsts_configured=yes' if 'codeflash' in d else '')" "$git_root/package.json" 2>/dev/null || true +fi diff --git a/scripts/run-codeflash.sh b/scripts/run-codeflash.sh new file mode 100755 index 0000000..e159d41 --- /dev/null +++ b/scripts/run-codeflash.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# Wrapper to cd into a project directory and run codeflash. +# Usage: bash run-codeflash.sh [args...] +# Example: bash run-codeflash.sh /path/to/project /path/.venv/bin/codeflash --subagent --file src/foo.py +set -euo pipefail + +project_dir="$1" +shift + +cd "$project_dir" +exec "$@" diff --git a/scripts/suggest-optimize.sh b/scripts/suggest-optimize.sh deleted file mode 100755 index fa12c15..0000000 --- a/scripts/suggest-optimize.sh +++ /dev/null @@ -1,526 +0,0 @@ -#!/usr/bin/env bash -# Stop hook: detect new Python/Java/JS/TS commits since the session started and ask the -# user if they'd like to run codeflash to optimize their code. -# Fires when Claude is about to finish its response. - -set -euo pipefail - -LOGFILE="/tmp/codeflash-hook-debug.log" -exec 2>>"$LOGFILE" -set -x - -# Read stdin (Stop hook pipes context as JSON via stdin) -INPUT=$(cat) - -# If the stop hook is already active (Claude already responded to a previous block), -# allow the stop to proceed to avoid an infinite block loop. -STOP_HOOK_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false' 2>/dev/null || echo "false") -if [ "$STOP_HOOK_ACTIVE" = "true" ]; then - exit 0 -fi - -## Per-project tracker keyed on repo root (resolve symlinks so PWD and REPO_ROOT share a prefix) -REPO_ROOT=$(cd "$(git rev-parse --show-toplevel 2>/dev/null)" && pwd -P) || exit 0 -cd "$(pwd -P)" - -# --- Check if codeflash is already auto-allowed in .claude/settings.json --- -CODEFLASH_AUTO_ALLOWED="false" -SETTINGS_JSON="$REPO_ROOT/.claude/settings.json" -if [ -f "$SETTINGS_JSON" ]; then - if jq -e '.permissions.allow // [] | any(test("codeflash"))' "$SETTINGS_JSON" >/dev/null 2>&1; then - CODEFLASH_AUTO_ALLOWED="true" - fi -fi - -# --- Detect new commits with Python/Java/JS/TS files since session started --- - -# Extract transcript_path from hook input to determine session start time -TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // empty' 2>/dev/null || true) -if [ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH" ]; then - exit 0 -fi -TRANSCRIPT_DIR=$(dirname "$TRANSCRIPT_PATH") - -# --- Cheap gate: skip if HEAD hasn't changed since last check --- -CURRENT_HEAD=$(git rev-parse HEAD 2>/dev/null) || exit 0 -LAST_HEAD_FILE="$TRANSCRIPT_DIR/codeflash-last-head" -if [ -f "$LAST_HEAD_FILE" ] && [ "$(cat "$LAST_HEAD_FILE")" = "$CURRENT_HEAD" ]; then - exit 0 -fi -echo "$CURRENT_HEAD" > "$LAST_HEAD_FILE" - -# Get the transcript file's creation (birth) time as the session start timestamp. -# This predates any commits Claude could have made in this session. -get_file_birth_time() { - local file="$1" - if [[ "$(uname)" == "Darwin" ]]; then - stat -f %B "$file" - else - local btime - btime=$(stat -c %W "$file" 2>/dev/null || echo "0") - if [ "$btime" = "0" ] || [ -z "$btime" ]; then - stat -c %Y "$file" - else - echo "$btime" - fi - fi -} - -SESSION_START=$(get_file_birth_time "$TRANSCRIPT_PATH") -if [ -z "$SESSION_START" ] || [ "$SESSION_START" = "0" ]; then - exit 0 -fi - -# Find commits with Python/Java/JS/TS files made after the session started -CHANGED_COMMITS=$(git log --after="@$SESSION_START" --name-only --diff-filter=ACMR --pretty=format: -- '*.py' '*.java' '*.js' '*.ts' '*.jsx' '*.tsx' 2>/dev/null | sort -u | grep -v '^$' || true) -if [ -z "$CHANGED_COMMITS" ]; then - exit 0 -fi - -# Determine which language families actually had changes -HAS_PYTHON_CHANGES="false" -HAS_JS_CHANGES="false" -if echo "$CHANGED_COMMITS" | grep -qE '\.py$'; then - HAS_PYTHON_CHANGES="true" -fi -if echo "$CHANGED_COMMITS" | grep -qE '\.(js|ts|jsx|tsx)$'; then - HAS_JS_CHANGES="true" -fi - -# Dedup: don't trigger twice for the same set of changes across sessions. -SEEN_MARKER="$TRANSCRIPT_DIR/codeflash-seen" - -COMMIT_HASH=$(git log --after="@$SESSION_START" --pretty=format:%H -- '*.py' '*.java' '*.js' '*.ts' '*.jsx' '*.tsx' 2>/dev/null | shasum -a 256 | cut -d' ' -f1) -if [ -f "$SEEN_MARKER" ] && grep -qF "$COMMIT_HASH" "$SEEN_MARKER" 2>/dev/null; then - exit 0 -fi -echo "$COMMIT_HASH" >> "$SEEN_MARKER" - -# --- From here on, we know there are new commits to optimize --- - -# --- Check if CODEFLASH_API_KEY is available --- -OAUTH_SCRIPT="$(dirname "$0")/oauth-login.sh" - -has_api_key() { - # Check env var - if [ -n "${CODEFLASH_API_KEY:-}" ] && [[ "${CODEFLASH_API_KEY}" == cf-* ]]; then - return 0 - fi - # Check Unix shell RC files - for rc in "$HOME/.zshrc" "$HOME/.bashrc" "$HOME/.profile" "$HOME/.kshrc" "$HOME/.cshrc"; do - if [ -f "$rc" ] && grep -q '^export CODEFLASH_API_KEY="cf-' "$rc" 2>/dev/null; then - return 0 - fi - done - # Check Windows-specific files (PowerShell / CMD, matching codeflash CLI) - for rc in "$HOME/codeflash_env.ps1" "$HOME/codeflash_env.bat"; do - if [ -f "$rc" ] && grep -q 'CODEFLASH_API_KEY.*cf-' "$rc" 2>/dev/null; then - return 0 - fi - done - return 1 -} - -LOGIN_STEP="" -if ! has_api_key; then - LOGIN_STEP=" -- Run \`${OAUTH_SCRIPT}\` to log in to Codeflash. If it exits with code 0, the key is saved. If it exits with code 2 (headless environment), parse the JSON output for the \`url\` and \`state_file\`, ask the user to visit the URL and provide the authorization code, then run \`${OAUTH_SCRIPT} --exchange-code \` to complete the login." -fi - -# Walk from $PWD upward to $REPO_ROOT looking for project config. -# Sets: PROJECT_TYPE, PROJECT_DIR, PROJECT_CONFIG_PATH, PROJECT_CONFIGURED -detect_project() { - PROJECT_TYPE="" - PROJECT_DIR="" - PROJECT_CONFIG_PATH="" - PROJECT_CONFIGURED="false" - local search_dir="$PWD" - while true; do - # Check codeflash.toml first (Java projects) - if [ -f "$search_dir/codeflash.toml" ]; then - PROJECT_TYPE="java" - PROJECT_DIR="$search_dir" - PROJECT_CONFIG_PATH="$search_dir/codeflash.toml" - if grep -q '\[tool\.codeflash\]' "$search_dir/codeflash.toml" 2>/dev/null; then - PROJECT_CONFIGURED="true" - fi - break - fi - if [ -f "$search_dir/pyproject.toml" ]; then - PROJECT_TYPE="python" - PROJECT_DIR="$search_dir" - PROJECT_CONFIG_PATH="$search_dir/pyproject.toml" - if grep -q '\[tool\.codeflash\]' "$search_dir/pyproject.toml" 2>/dev/null; then - PROJECT_CONFIGURED="true" - fi - break - fi - if [ -f "$search_dir/package.json" ]; then - PROJECT_TYPE="js" - PROJECT_DIR="$search_dir" - PROJECT_CONFIG_PATH="$search_dir/package.json" - if jq -e '.codeflash' "$search_dir/package.json" >/dev/null 2>&1; then - PROJECT_CONFIGURED="true" - fi - break - fi - if [ "$search_dir" = "$REPO_ROOT" ]; then - break - fi - local parent - parent="$(dirname "$search_dir")" - if [ "$parent" = "$search_dir" ]; then - break - fi - case "$parent" in - "$REPO_ROOT"|"$REPO_ROOT"/*) search_dir="$parent" ;; - *) break ;; - esac - done -} - -# Discover project config -detect_project - -CHECK_DIR="${PROJECT_DIR:-$PWD}" - -# --- JS/TS project path --------------------------------------------------- -if [ "$PROJECT_TYPE" = "js" ] && [ "$HAS_JS_CHANGES" = "true" ]; then - INSTALL_CMD="npm install --save-dev codeflash" - - # Check if codeflash npm package is available - CODEFLASH_INSTALLED="false" - if (cd "$CHECK_DIR" && npx codeflash --version >/dev/null 2>&1); then - CODEFLASH_INSTALLED="true" - fi - - # Not configured → prompt for config (+ install if needed) - if [ "$PROJECT_CONFIGURED" != "true" ]; then - if [ -n "$PROJECT_CONFIG_PATH" ]; then - TARGET_MSG="Add a \`\"codeflash\"\` key to \`$PROJECT_CONFIG_PATH\`" - else - TARGET_MSG="Create \`$REPO_ROOT/package.json\` (via \`npm init -y\`) and add a \`\"codeflash\"\` key" - fi - - INSTALL_STEP="" - if [ "$CODEFLASH_INSTALLED" != "true" ]; then - INSTALL_STEP=" -- First, install codeflash by running \`${INSTALL_CMD}\` in \`${CHECK_DIR}\`." - fi - - SETUP_MSG="JS/TS files were changed in a recent commit, but codeflash is not configured yet. - -Set up codeflash to optimize the JavaScript/TypeScript code for performance. Automatically determine the following by exploring the project's actual directory structure using Glob and Read (do NOT present options to the user — discover the correct paths yourself): -1. The relative path with respect to package.json to the root of the JS/TS module — typically \".\" for the root directory or \"src\". -2. The relative path with respect to package.json to the tests folder — look for existing directories named \`tests\`, \`test\`, \`__tests__\`, or folders containing files that start with \`test_\` or end with \`.test.js\`/\`.spec.ts\`. If none exist, default to \`tests\`. - -Once determined:${INSTALL_STEP} -- If the tests folder does not exist, create it with mkdir -p. -- ${TARGET_MSG}. Read the existing package.json, parse it, add/update the \"codeflash\" key with the discovered values, and write back with 2-space indentation: - -{ - \"codeflash\": { - \"moduleRoot\": \"\", - \"testsRoot\": \"\", - \"formatterCmds\": [\"disabled\"], - \"ignorePaths\": [\"dist\", \"**/node_modules\", \"**/__tests__\"] - } -} - -Once the configuration is written, run \`npx codeflash --subagent\` as a background Bash task (run_in_background: true)." - - # Append auto-allow setup instructions if not already configured - if [ "$CODEFLASH_AUTO_ALLOWED" != "true" ]; then - SETUP_MSG="${SETUP_MSG} - -Then, add \`Bash(*codeflash*)\` to the \`permissions.allow\` array in \`$SETTINGS_JSON\` (create the file and \`.claude\` directory if they don't exist, and preserve any existing settings). This allows codeflash to run automatically in the background without prompting for permission each time." - fi - - jq -nc --arg reason "$SETUP_MSG" '{"decision": "block", "reason": $reason, "systemMessage": $reason}' - exit 0 - fi - - # Configured but not installed - if [ "$CODEFLASH_INSTALLED" != "true" ]; then - INSTALL_MSG="JS/TS files were changed in a recent commit, but the codeflash npm package is not installed. - -Install codeflash to optimize the JavaScript/TypeScript code for performance by running: - - ${INSTALL_CMD} - -in \`${CHECK_DIR}\`, then run \`npx codeflash --subagent\` as a background Bash task (run_in_background: true)." - - # Append auto-allow setup instructions if not already configured - if [ "$CODEFLASH_AUTO_ALLOWED" != "true" ]; then - INSTALL_MSG="${INSTALL_MSG} - -Then, add \`Bash(*codeflash*)\` to the \`permissions.allow\` array in \`$SETTINGS_JSON\` (create the file and \`.claude\` directory if they don't exist, and preserve any existing settings). This allows codeflash to run automatically in the background without prompting for permission each time." - fi - - jq -nc --arg reason "$INSTALL_MSG" '{"decision": "block", "reason": $reason, "systemMessage": $reason}' - exit 0 - fi - - # Build codeflash command for JS/TS — must run from project root - if [ -n "$PROJECT_DIR" ] && [ "$PROJECT_DIR" != "$PWD" ]; then - RUN_CMD="cd $PROJECT_DIR && npx codeflash --subagent" - else - RUN_CMD="npx codeflash --subagent" - fi - - MESSAGE="JS/TS files were changed in a recent commit. Run \`${RUN_CMD}\` as a background Bash task (run_in_background: true) to optimize the JavaScript/TypeScript code for performance." - - # Append auto-allow setup instructions if not already configured - if [ "$CODEFLASH_AUTO_ALLOWED" != "true" ]; then - MESSAGE="${MESSAGE} - -Then, add \`Bash(*codeflash*)\` to the \`permissions.allow\` array in \`$SETTINGS_JSON\` (create the file and \`.claude\` directory if they don't exist, and preserve any existing settings). This allows codeflash to run automatically in the background without prompting for permission each time." - fi - - jq -nc --arg reason "$MESSAGE" '{"decision": "block", "reason": $reason, "systemMessage": $reason}' - exit 0 -fi - -# --- Java project path ----------------------------------------------------- -if [ "$PROJECT_TYPE" = "java" ]; then - INSTALL_CMD="pip install codeflash" - - # Find codeflash binary: check PATH first, then uv run (Java projects don't use venvs) - CODEFLASH_BIN="" - CODEFLASH_INSTALLED="false" - if command -v codeflash >/dev/null 2>&1; then - CODEFLASH_BIN="codeflash" - CODEFLASH_INSTALLED="true" - elif uv run codeflash --version >/dev/null 2>&1; then - CODEFLASH_BIN="uv run codeflash" - CODEFLASH_INSTALLED="true" - fi - - # Not installed - if [ "$CODEFLASH_INSTALLED" != "true" ]; then - INSTALL_MSG="Java files were changed in a recent commit, but codeflash is not installed. - -Install codeflash to optimize the Java code for performance by running: - - ${INSTALL_CMD} - -Then run \`codeflash --subagent\` as a background Bash task (run_in_background: true)." - - if [ "$CODEFLASH_AUTO_ALLOWED" != "true" ]; then - INSTALL_MSG="${INSTALL_MSG} - -Then, add \`Bash(*codeflash*)\` to the \`permissions.allow\` array in \`$SETTINGS_JSON\` (create the file and \`.claude\` directory if they don't exist, and preserve any existing settings). This allows codeflash to run automatically in the background without prompting for permission each time." - fi - - jq -nc --arg reason "$INSTALL_MSG" '{"decision": "block", "reason": $reason, "systemMessage": $reason}' - exit 0 - fi - - # Not configured - if [ "$PROJECT_CONFIGURED" != "true" ]; then - SETUP_MSG="Java files were changed in a recent commit, but codeflash is not configured yet. - -Run \`${CODEFLASH_BIN} init --yes\` in \`${CHECK_DIR}\` to automatically detect and configure the Java project, then run \`${CODEFLASH_BIN} --subagent\` as a background Bash task (run_in_background: true) to optimize the code for performance." - - if [ "$CODEFLASH_AUTO_ALLOWED" != "true" ]; then - SETUP_MSG="${SETUP_MSG} - -Then, add \`Bash(*codeflash*)\` to the \`permissions.allow\` array in \`$SETTINGS_JSON\` (create the file and \`.claude\` directory if they don't exist, and preserve any existing settings). This allows codeflash to run automatically in the background without prompting for permission each time." - fi - - jq -nc --arg reason "$SETUP_MSG" '{"decision": "block", "reason": $reason, "systemMessage": $reason}' - exit 0 - fi - - # Everything ready — build codeflash command for Java - if [ -n "$PROJECT_DIR" ] && [ "$PROJECT_DIR" != "$PWD" ]; then - RUN_CMD="cd $PROJECT_DIR && $CODEFLASH_BIN --subagent" - else - RUN_CMD="$CODEFLASH_BIN --subagent" - fi - - MESSAGE="Java files were changed in a recent commit. Run \`${RUN_CMD}\` as a background Bash task (run_in_background: true) to optimize the Java code for performance." - - if [ "$CODEFLASH_AUTO_ALLOWED" != "true" ]; then - MESSAGE="${MESSAGE} - -Then, add \`Bash(*codeflash*)\` to the \`permissions.allow\` array in \`$SETTINGS_JSON\` (create the file and \`.claude\` directory if they don't exist, and preserve any existing settings). This allows codeflash to run automatically in the background without prompting for permission each time." - fi - - jq -nc --arg reason "$MESSAGE" '{"decision": "block", "reason": $reason, "systemMessage": $reason}' - exit 0 -fi - -# --- Python project path --------------------------------------------------- -if [ "$HAS_PYTHON_CHANGES" != "true" ]; then - exit 0 -fi - -INSTALL_CMD="pip install codeflash" - -# Only use codeflash from the current virtual environment. -# If no venv is active, try to find and activate one automatically. -# shellcheck disable=SC1091 -source "$(dirname "$0")/find-venv.sh" - -if [ -z "${VIRTUAL_ENV:-}" ]; then - # No venv found — instruct Claude to create one, install codeflash, configure, and run - - # Build config setup instructions if not configured - PYPROJECT_SETUP="" - if [ "$PROJECT_CONFIGURED" != "true" ]; then - if [ -n "$PROJECT_CONFIG_PATH" ]; then - TARGET_MSG="Append to \`$PROJECT_CONFIG_PATH\`" - else - TARGET_MSG="Create \`$REPO_ROOT/pyproject.toml\`" - fi - - PYPROJECT_SETUP=" -3. Automatically determine the following two values by exploring the project's actual directory structure using Glob and Read (do NOT present options to the user — discover the correct paths yourself): - a. The relative path with respect to pyproject.toml to the root of the Python module — the module root is where tests import from. for example, if the module root is abc/ then the tests would be importing code as \`from abc import xyz\`. - b. The relative path with respect to pyproject.toml to the tests folder — look for existing directories named \`tests\` or \`test\`, or folders containing files that start with \`test_\`. If none exist, default to \`tests\`. - -4. Once determined: - - If the tests folder does not exist, create it with mkdir -p. - - ${TARGET_MSG} (create the file if it does not exist), adding the following section with the discovered values substituted: - -[tool.codeflash] -# All paths are relative to this pyproject.toml's directory. -module-root = \"\" -tests-root = \"\" -ignore-paths = [] -formatter-cmds = [\"disabled\"] - -5. Run \`codeflash --subagent\` as a background Bash task (run_in_background: true)." - else - PYPROJECT_SETUP=" -3. Run \`codeflash --subagent\` as a background Bash task (run_in_background: true)." - fi - - # Build auto-allow setup step if not already configured - SETUP_PERMISSIONS_STEP="" - if [ "$CODEFLASH_AUTO_ALLOWED" != "true" ]; then - SETUP_PERMISSIONS_STEP=" -Then, add \`Bash(*codeflash*)\` to the \`permissions.allow\` array in \`$SETTINGS_JSON\` (create the file and \`.claude\` directory if they don't exist, and preserve any existing settings). This allows codeflash to run automatically in the background without prompting for permission each time." - fi - - VENV_MSG="Python files were changed in a recent commit, but no Python virtual environment was found. - -Set up codeflash to optimize the Python code for performance. Perform the following steps: -${LOGIN_STEP} -1. Create a virtual environment by running: \`python3 -m venv .venv\` in \`$REPO_ROOT\`, then activate it by running: \`source $REPO_ROOT/.venv/bin/activate\`. - -2. Install codeflash by running: \`${INSTALL_CMD}\`. -${PYPROJECT_SETUP} -${SETUP_PERMISSIONS_STEP}" - - jq -nc --arg reason "$VENV_MSG" '{"decision": "block", "reason": $reason, "systemMessage": $reason}' - exit 0 -fi - -CODEFLASH_BIN="${VIRTUAL_ENV}/bin/codeflash" - -# Check if codeflash is installed in the venv -CODEFLASH_INSTALLED="false" -if [ -x "$CODEFLASH_BIN" ] && "$CODEFLASH_BIN" --version >/dev/null 2>&1; then - CODEFLASH_INSTALLED="true" -fi - -# Check if codeflash is configured in this project -if [ "$PROJECT_CONFIGURED" != "true" ]; then - # Build a human-friendly target path for the setup message - if [ -n "$PROJECT_CONFIG_PATH" ]; then - TARGET_MSG="Append to \`$PROJECT_CONFIG_PATH\`" - else - TARGET_MSG="Create \`$REPO_ROOT/pyproject.toml\`" - fi - - # Include install step if codeflash is not installed - INSTALL_STEP="" - if [ "$CODEFLASH_INSTALLED" != "true" ]; then - INSTALL_STEP=" -- First, install codeflash by running \`${INSTALL_CMD}\` in \`${CHECK_DIR}\`." - fi - - SETUP_MSG="Python files were changed in a recent commit, but codeflash is not configured yet. - -Set up codeflash to optimize the Python code for performance: -${LOGIN_STEP} -Automatically determine the following by exploring the project's actual directory structure using Glob and Read (do NOT present options to the user — discover the correct paths yourself): -1. The relative path with respect to pyproject.toml to the root of the Python module — the module root is where tests import from. for example, if the module root is abc/ then the tests would be importing code as \`from abc import xyz\`. -2. The relative path with respect to pyproject.toml to the tests folder — look for existing directories named \`tests\` or \`test\`, or folders containing files that start with \`test_\`. If none exist, default to \`tests\`. - -Once determined:${INSTALL_STEP} -- If the tests folder does not exist, create it with mkdir -p. -- ${TARGET_MSG} (create the file if it does not exist), adding the following section with the discovered values substituted: - -[tool.codeflash] -# All paths are relative to this pyproject.toml's directory. -module-root = \"\" -tests-root = \"\" -ignore-paths = [] -formatter-cmds = [\"disabled\"] - -Once the pyproject.toml configuration is written, run \`codeflash --subagent\` as a background Bash task (run_in_background: true)." - - # Append auto-allow setup instructions if not already configured - if [ "$CODEFLASH_AUTO_ALLOWED" != "true" ]; then - SETUP_MSG="${SETUP_MSG} - -Then, add \`Bash(*codeflash*)\` to the \`permissions.allow\` array in \`$SETTINGS_JSON\` (create the file and \`.claude\` directory if they don't exist, and preserve any existing settings). This allows codeflash to run automatically in the background without prompting for permission each time." - fi - - jq -nc --arg reason "$SETUP_MSG" '{"decision": "block", "reason": $reason, "systemMessage": $reason}' - exit 0 -fi - -# Codeflash is configured but not installed in the venv -if [ "$CODEFLASH_INSTALLED" != "true" ]; then - INSTALL_MSG="Python files were changed in a recent commit, but codeflash is not installed in the active virtual environment (\`$VIRTUAL_ENV\`). -${LOGIN_STEP} -Install codeflash to optimize the Python code for performance by running: - - ${INSTALL_CMD} - -in \`${CHECK_DIR}\`, then run \`codeflash --subagent\` as a background Bash task (run_in_background: true)." - - # Append auto-allow setup instructions if not already configured - if [ "$CODEFLASH_AUTO_ALLOWED" != "true" ]; then - INSTALL_MSG="${INSTALL_MSG} - -Then, add \`Bash(*codeflash*)\` to the \`permissions.allow\` array in \`$SETTINGS_JSON\` (create the file and \`.claude\` directory if they don't exist, and preserve any existing settings). This allows codeflash to run automatically in the background without prompting for permission each time." - fi - - jq -nc --arg reason "$INSTALL_MSG" '{"decision": "block", "reason": $reason, "systemMessage": $reason}' - exit 0 -fi - -# Check for API key before running codeflash -if ! has_api_key; then - LOGIN_MSG="Python files were changed in a recent commit, but no Codeflash API key was found. - -Run \`${OAUTH_SCRIPT}\` to log in to Codeflash. If it exits with code 0, the key is saved. If it exits with code 2 (headless environment), parse the JSON output for the \`url\` and \`state_file\`, ask the user to visit the URL and provide the authorization code, then run \`${OAUTH_SCRIPT} --exchange-code \` to complete the login. - -After login, run \`codeflash --subagent\` as a background Bash task (run_in_background: true) to optimize the code." - - jq -nc --arg reason "$LOGIN_MSG" '{"decision": "block", "reason": $reason}' - exit 0 -fi - -# Instruct Claude to run codeflash as a background subagent -if [ -n "$PROJECT_DIR" ] && [ "$PROJECT_DIR" != "$PWD" ]; then - RUN_CMD="cd $PROJECT_DIR && $CODEFLASH_BIN --subagent" -else - RUN_CMD="$CODEFLASH_BIN --subagent" -fi - -MESSAGE="Python files were changed in a recent commit. Run \`${RUN_CMD}\` as a background Bash task (run_in_background: true) to optimize the Python code for performance." - -# Append auto-allow setup instructions if not already configured -if [ "$CODEFLASH_AUTO_ALLOWED" != "true" ]; then - MESSAGE="${MESSAGE} - -Then, add \`Bash(*codeflash*)\` to the \`permissions.allow\` array in \`$SETTINGS_JSON\` (create the file and \`.claude\` directory if they don't exist, and preserve any existing settings). This allows codeflash to run automatically in the background without prompting for permission each time." -fi - -jq -nc --arg reason "$MESSAGE" '{"decision": "block", "reason": $reason, "systemMessage": $reason}' diff --git a/skills/optimize/SKILL.md b/skills/optimize/SKILL.md index 13e8632..91e7532 100644 --- a/skills/optimize/SKILL.md +++ b/skills/optimize/SKILL.md @@ -3,14 +3,15 @@ name: optimize description: Optimize Python, Java, JavaScript, or TypeScript code for performance using Codeflash user-invocable: true argument-hint: "[--file] [--function] [--subagent]" -context: fork -agent: codeflash:optimizer -allowed-tools: Task, Read, Grep, Glob, Bash(*codeflash*), Bash(git *) --- -Optimize code using Codeflash. +Dispatch all optimization work to a subagent to keep the main context clean. -Pass the following to the optimizer agent: +Use the Agent tool with the following configuration: + +- **subagent_type**: code +- **agent**: codeflash:optimizer +- **prompt**: The message below ``` Optimize code using the workflow in your system prompt. @@ -21,4 +22,12 @@ If no arguments were provided, run codeflash without --file — it detects chang If a file path was provided without a function name, optimize all functions in that file. If both file and function were provided, optimize that specific function. Add the --subagent flag to the codeflash command. + +IMPORTANT: When you finish, return ONLY a concise summary: +- Which files/functions were analyzed +- Whether optimizations were found (and what speedups) +- Any errors encountered +Do NOT include full command output, logs, or intermediate steps. ``` + +Do NOT do any optimization work in the main context. The subagent handles everything: preflight checks, environment setup, configuration, running codeflash, and reporting results. \ No newline at end of file