diff --git a/.claude/settings.json b/.claude/settings.json index 30a12bc1..ab2889f8 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -5,7 +5,7 @@ "hooks": [ { "type": "command", - "command": "cd \"$(git rev-parse --show-toplevel)\" && uv run --script ci/hooks/board_context.py", + "command": "cd \"$(git rev-parse --show-toplevel)\" && uv run --no-project --script ci/hooks/board_context.py", "timeout": 5 } ] @@ -17,7 +17,7 @@ "hooks": [ { "type": "command", - "command": "cd \"$(git rev-parse --show-toplevel)\" && uv run --script ci/hooks/tool_guard.py", + "command": "cd \"$(git rev-parse --show-toplevel)\" && uv run --no-project --script ci/hooks/tool_guard.py", "timeout": 5 } ] @@ -29,12 +29,12 @@ "hooks": [ { "type": "command", - "command": "cd \"$(git rev-parse --show-toplevel)\" && uv run --script ci/hooks/lint.py", + "command": "cd \"$(git rev-parse --show-toplevel)\" && uv run --no-project --script ci/hooks/lint.py", "timeout": 120 }, { "type": "command", - "command": "cd \"$(git rev-parse --show-toplevel)\" && uv run --script ci/hooks/readme_guard.py", + "command": "cd \"$(git rev-parse --show-toplevel)\" && uv run --no-project --script ci/hooks/readme_guard.py", "timeout": 5 } ] @@ -45,7 +45,7 @@ "hooks": [ { "type": "command", - "command": "cd \"$(git rev-parse --show-toplevel)\" && uv run --script ci/hooks/check-on-start.py", + "command": "cd \"$(git rev-parse --show-toplevel)\" && uv run --no-project --script ci/hooks/check-on-start.py", "timeout": 10 } ] @@ -56,12 +56,12 @@ "hooks": [ { "type": "command", - "command": "cd \"$(git rev-parse --show-toplevel)\" && uv run --script ci/hooks/code-review-on-stop.py", + "command": "cd \"$(git rev-parse --show-toplevel)\" && uv run --no-project --script ci/hooks/code-review-on-stop.py", "timeout": 10 }, { "type": "command", - "command": "cd \"$(git rev-parse --show-toplevel)\" && uv run --script ci/hooks/check-on-stop.py", + "command": "cd \"$(git rev-parse --show-toplevel)\" && uv run --no-project --script ci/hooks/check-on-stop.py", "timeout": 120 } ] diff --git a/.gitignore b/.gitignore index c1bd2f19..ddd38192 100644 --- a/.gitignore +++ b/.gitignore @@ -79,3 +79,4 @@ tasks/loop-runs/ # clud project settings !.clud/ !.clud/settings.json +.claude/tmp/ diff --git a/ci/hooks/lint.py b/ci/hooks/lint.py index e19e63c6..bd821409 100644 --- a/ci/hooks/lint.py +++ b/ci/hooks/lint.py @@ -35,12 +35,11 @@ def main(): if not file_path: return 0 - # Normalize path - file_path = file_path.replace("\\", "/") - # Resolve relative paths against project root if not os.path.isabs(file_path): - file_path = os.path.join(str(PROJECT_ROOT), file_path).replace("\\", "/") + file_path = os.path.join(str(PROJECT_ROOT), file_path) + + file_path = os.path.realpath(file_path) # Only lint Rust files if not file_path.endswith(".rs"): @@ -50,10 +49,22 @@ def main(): if not os.path.isfile(file_path): return 0 - # Delegate to ./lint in single-file mode + # Skip files outside this project (e.g. when editing inside a worktree + # of another repo). detect_crate() would otherwise read the worktree's + # `crates/` segment and run clippy with -p against fbuild, which + # either fails or — when names collide — lints the wrong code. + project_root_real = os.path.normcase(os.path.realpath(str(PROJECT_ROOT))) + file_path_check = os.path.normcase(file_path) + if os.path.commonpath([project_root_real, file_path_check]) != project_root_real: + return 0 + + # Delegate to ./lint in single-file mode. Use the active interpreter + # directly instead of `uv run --script` so we don't trigger another + # editable-build of the fbuild project (which would re-run + # `soldr cargo build --release -p fbuild-cli` on every Edit). lint_script = str(PROJECT_ROOT / "lint") result = subprocess.run( - ["uv", "run", "--script", lint_script, file_path], + [sys.executable, lint_script, file_path], capture_output=True, text=True, encoding="utf-8",