Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
__pycache__/
*.pyc
.orphaned_at
.idea/
.claude/settings.local.json
24 changes: 12 additions & 12 deletions agents/optimizer.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,13 +227,13 @@ When configuration is missing, automatically discover the paths:

Do NOT ask the user to choose from a list of options. Use your tools to inspect the actual project structure and determine the correct paths.

3. **Write the configuration**: Append the `[tool.codeflash]` section to the target `pyproject.toml`. Use exactly this format, substituting the user's answers:
3. **Write the configuration**: Append the `[tool.codeflash]` section to the target `pyproject.toml`. Use exactly this format, substituting the discovered paths:

```toml
[tool.codeflash]
# All paths are relative to this pyproject.toml's directory.
module-root = "<user's module root>"
tests-root = "<user's tests folder>"
module-root = "<discovered module root>"
tests-root = "<discovered tests folder>"
ignore-paths = []
formatter-cmds = ["disabled"]
```
Expand All @@ -250,21 +250,21 @@ Use the `package.json` discovered in Step 1:
- **If `package.json` exists but has no `"codeflash"` key** → add the config to that file.
- **If no `package.json` was found** → create one at the git repository root with `npm init -y`, then add the config.

When configuration is missing, interactively set it up:
When configuration is missing, automatically discover the paths:

1. **Discover module root**: Use Glob and Read to find the relative path to the root of the JavaScript/TypeScript module. Typically `.` for the root directory or `src`. Look for source files, `index.js`/`index.ts`, or directories containing the main entry point referenced in `package.json`.

1. **Ask the user two questions** (use AskUserQuestion or prompt directly):
- **Module root**: "What is the relative path to the root of your JavaScript/TypeScript module?" (e.g. `.` for the root directory, `src`, `src/lib`)
- **Tests folder**: "What is the relative path to your tests folder?" (e.g. `tests`, `test`, `__tests__`, `src/__tests__`)
2. **Discover tests folder**: Use Glob to find the relative path to the tests directory. Look for existing directories named `tests`, `test`, `__tests__`, or folders containing files that start with `test_` or end with `.test.js`/`.test.ts`/`.spec.js`/`.spec.ts`. If no tests directory exists, default to `tests` and create it with `mkdir -p`.

2. **Validate directories**: Check whether the tests folder the user provided exists. If it does **not** exist, create it with `mkdir -p`.
Do NOT ask the user to choose from a list of options. Use your tools to inspect the actual project structure and determine the correct paths.

3. **Write the configuration**: Read the existing `package.json`, parse it as JSON, add a `"codeflash"` key at the root level, and write the file back. Use exactly this structure, substituting the user's answers:
3. **Write the configuration**: Read the existing `package.json`, parse it as JSON, add a `"codeflash"` key at the root level, and write the file back. Use exactly this structure, substituting the discovered paths:

```json
{
"codeflash": {
"moduleRoot": "<user's module root>",
"testsRoot": "<user's tests folder>",
"moduleRoot": "<discovered module root>",
"testsRoot": "<discovered tests folder>",
"formatterCmds": ["disabled"],
"ignorePaths": ["dist", "**/node_modules", "**/__tests__"]
}
Expand Down Expand Up @@ -375,6 +375,6 @@ Do not wait for the background task to finish. The user will be notified automat

- **No virtual environment**: No `$VIRTUAL_ENV` set and no `.venv`/`venv` directory found — tell the user to create/activate a venv, install codeflash there, and restart Claude Code
- **Exit 127 / command not found**: Codeflash not installed in the active venv — ask the user to install it with `pip install codeflash`
- **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)
- **Not configured**: Automatically discover module root and tests folder using Glob and Read, 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
22 changes: 11 additions & 11 deletions scripts/oauth-login.sh
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ if [ "${1:-}" = "--exchange-code" ]; then
fi

# Read saved state
CODE_VERIFIER=$(python3 -c "import json; print(json.load(open('${STATE_FILE}')).get('code_verifier',''))" 2>/dev/null || true)
REMOTE_REDIRECT=$(python3 -c "import json; print(json.load(open('${STATE_FILE}')).get('remote_redirect_uri',''))" 2>/dev/null || true)
CODE_VERIFIER=$(python3 -c "import json,sys; print(json.load(open(sys.argv[1])).get('code_verifier',''))" "$STATE_FILE" 2>/dev/null || true)
REMOTE_REDIRECT=$(python3 -c "import json,sys; print(json.load(open(sys.argv[1])).get('remote_redirect_uri',''))" "$STATE_FILE" 2>/dev/null || true)

rm -f "$STATE_FILE"

Expand Down Expand Up @@ -159,8 +159,8 @@ PORT=$(python3 -c "import socket; s=socket.socket(); s.bind(('',0)); print(s.get

LOCAL_REDIRECT_URI="http://localhost:${PORT}/callback"
REMOTE_REDIRECT_URI="${CFWEBAPP_BASE_URL}/codeflash/auth/callback"
ENCODED_LOCAL_REDIRECT=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${LOCAL_REDIRECT_URI}'))")
ENCODED_REMOTE_REDIRECT=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${REMOTE_REDIRECT_URI}'))")
ENCODED_LOCAL_REDIRECT=$(python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1]))" "$LOCAL_REDIRECT_URI")
ENCODED_REMOTE_REDIRECT=$(python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1]))" "$REMOTE_REDIRECT_URI")

AUTH_PARAMS="response_type=code&client_id=${CLIENT_ID}&code_challenge=${CODE_CHALLENGE}&code_challenge_method=sha256&state=${STATE}"
LOCAL_AUTH_URL="${CFWEBAPP_BASE_URL}/codeflash/auth?${AUTH_PARAMS}&redirect_uri=${ENCODED_LOCAL_REDIRECT}"
Expand All @@ -171,13 +171,13 @@ if ! can_open_browser; then
# Save PKCE state so --exchange-code can complete the flow later
HEADLESS_STATE_FILE=$(mktemp /tmp/codeflash-oauth-state-XXXXXX.json)
python3 -c "
import json
import json, sys
json.dump({
'code_verifier': '${CODE_VERIFIER}',
'remote_redirect_uri': '${REMOTE_REDIRECT_URI}',
'state': '${STATE}'
}, open('${HEADLESS_STATE_FILE}', 'w'))
"
'code_verifier': sys.argv[1],
'remote_redirect_uri': sys.argv[2],
'state': sys.argv[3]
}, open(sys.argv[4], 'w'))
" "$CODE_VERIFIER" "$REMOTE_REDIRECT_URI" "$STATE" "$HEADLESS_STATE_FILE"
# Output JSON for Claude to parse — this is the ONLY stdout in headless mode
printf '{"headless":true,"url":"%s","state_file":"%s"}\n' "$REMOTE_AUTH_URL" "$HEADLESS_STATE_FILE"
exit 2
Expand Down Expand Up @@ -388,7 +388,7 @@ if [ ! -s "$RESULT_FILE" ]; then
fi

# --- Parse callback result ---
AUTH_CODE=$(python3 -c "import json; print(json.load(open('${RESULT_FILE}')).get('code',''))" 2>/dev/null || true)
AUTH_CODE=$(python3 -c "import json,sys; print(json.load(open(sys.argv[1])).get('code',''))" "$RESULT_FILE" 2>/dev/null || true)

if [ -z "$AUTH_CODE" ]; then
kill "$SERVER_PID" 2>/dev/null || true
Expand Down
142 changes: 51 additions & 91 deletions scripts/suggest-optimize.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@

set -euo pipefail

LOGFILE="/tmp/codeflash-hook-debug.log"
exec 2>>"$LOGFILE"
set -x
# Debug logging — only enabled when CODEFLASH_HOOK_DEBUG=1
if [ "${CODEFLASH_HOOK_DEBUG:-}" = "1" ]; then
LOGFILE="${CODEFLASH_HOOK_LOGFILE:-/tmp/codeflash-hook-debug.log}"
exec 2>>"$LOGFILE"
set -x
fi

# Read stdin (Stop hook pipes context as JSON via stdin)
INPUT=$(cat)
Expand Down Expand Up @@ -72,18 +75,18 @@ if [ -z "$SESSION_START" ] || [ "$SESSION_START" = "0" ]; then
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
CHANGED_FILES=$(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_FILES" ]; 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
if echo "$CHANGED_FILES" | grep -qE '\.py$'; then
HAS_PYTHON_CHANGES="true"
fi
if echo "$CHANGED_COMMITS" | grep -qE '\.(js|ts|jsx|tsx)$'; then
if echo "$CHANGED_FILES" | grep -qE '\.(js|ts|jsx|tsx)$'; then
HAS_JS_CHANGES="true"
fi

Expand Down Expand Up @@ -127,6 +130,24 @@ if ! has_api_key; then
- 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 <state_file> <code>\` to complete the login."
fi

# --- Helper: append auto-allow instructions if not already configured ---
# Usage: append_auto_allow_msg MSG_VAR_NAME
# Appends the auto-allow setup instructions to the variable named MSG_VAR_NAME
# if codeflash is not already auto-allowed in .claude/settings.json.
append_auto_allow_msg() {
if [ "$CODEFLASH_AUTO_ALLOWED" != "true" ]; then
local current="${!1}"
printf -v "$1" '%s\n\nThen, add `Bash(*codeflash*)` to the `permissions.allow` array in `%s` (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.' "$current" "$SETTINGS_JSON"
fi
}

# --- Helper: emit a block decision as JSON and exit ---
# Usage: emit_block "$MESSAGE"
emit_block() {
jq -nc --arg reason "$1" '{"decision": "block", "reason": $reason, "systemMessage": $reason}'
exit 0
}

# Walk from $PWD upward to $REPO_ROOT looking for project config.
# Sets: PROJECT_TYPE, PROJECT_DIR, PROJECT_CONFIG_PATH, PROJECT_CONFIGURED
detect_project() {
Expand Down Expand Up @@ -229,15 +250,8 @@ Once determined:${INSTALL_STEP}

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
append_auto_allow_msg SETUP_MSG
emit_block "$SETUP_MSG"
fi

# Configured but not installed
Expand All @@ -250,35 +264,21 @@ Install codeflash to optimize the JavaScript/TypeScript code for performance by

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
append_auto_allow_msg INSTALL_MSG
emit_block "$INSTALL_MSG"
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"
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
append_auto_allow_msg MESSAGE
emit_block "$MESSAGE"
fi

# --- Java project path -----------------------------------------------------
Expand Down Expand Up @@ -306,14 +306,8 @@ Install codeflash to optimize the Java code for performance by running:

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
append_auto_allow_msg INSTALL_MSG
emit_block "$INSTALL_MSG"
fi

# Not configured
Expand All @@ -322,33 +316,21 @@ Then, add \`Bash(*codeflash*)\` to the \`permissions.allow\` array in \`$SETTING

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
append_auto_allow_msg SETUP_MSG
emit_block "$SETUP_MSG"
fi

# Everything ready — build codeflash command for Java
if [ -n "$PROJECT_DIR" ] && [ "$PROJECT_DIR" != "$PWD" ]; then
RUN_CMD="cd $PROJECT_DIR && $CODEFLASH_BIN --subagent"
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
append_auto_allow_msg MESSAGE
emit_block "$MESSAGE"
fi

# --- Python project path ---------------------------------------------------
Expand Down Expand Up @@ -414,8 +396,7 @@ ${LOGIN_STEP}
${PYPROJECT_SETUP}
${SETUP_PERMISSIONS_STEP}"

jq -nc --arg reason "$VENV_MSG" '{"decision": "block", "reason": $reason, "systemMessage": $reason}'
exit 0
emit_block "$VENV_MSG"
fi

CODEFLASH_BIN="${VIRTUAL_ENV}/bin/codeflash"
Expand Down Expand Up @@ -463,15 +444,8 @@ 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
append_auto_allow_msg SETUP_MSG
emit_block "$SETUP_MSG"
fi

# Codeflash is configured but not installed in the venv
Expand All @@ -484,15 +458,8 @@ Install codeflash to optimize the Python code for performance by running:

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
append_auto_allow_msg INSTALL_MSG
emit_block "$INSTALL_MSG"
fi

# Check for API key before running codeflash
Expand All @@ -503,24 +470,17 @@ Run \`${OAUTH_SCRIPT}\` to log in to Codeflash. If it exits with code 0, the key

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
emit_block "$LOGIN_MSG"
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"
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}'
append_auto_allow_msg MESSAGE
emit_block "$MESSAGE"
Loading
Loading