fix(installer): use relative paths for hook commands in settings.local.json#549
fix(installer): use relative paths for hook commands in settings.local.json#549riaworks wants to merge 1 commit intoSynkraAI:mainfrom
Conversation
…l.json The installer generated platform-specific hook commands that caused issues: - Windows: absolute paths with escaped backslashes (machine-dependent, fragile) - Unix: $CLAUDE_PROJECT_DIR variable (known bugs GH #6023/#5814) Both approaches led to UserPromptSubmit hook errors in installed projects. Changes: - Use relative path `node .claude/hooks/<file>` on all platforms - Remove hardcoded `timeout: 10` from HOOK_EVENT_MAP and generated settings (Claude Code manages hook timeouts natively, each hook has internal safety) - Remove unused `isWindows` and `hookFilePath` variables - Update tests to reflect timeout removal The HOOK_EVENT_MAP event routing (MIS-3.1) remains unchanged — precompact is correctly mapped to PreCompact, not UserPromptSubmit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@riaworks is attempting to deploy a commit to the Pedro Valério Lopez's projects Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughRemoved timeout properties from hook configurations (HOOK_EVENT_MAP and DEFAULT_HOOK_CONFIG) and simplified hookCommand path construction from conditional Windows-specific absolute paths to uniform relative paths across all platforms. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/installer/src/wizard/ide-config-generator.js`:
- Around line 791-795: hookCommand currently interpolates hookFileName directly
(const hookCommand = `node .claude/hooks/${hookFileName}`), which allows
filenames with spaces or shell metacharacters to slip through; validate
hookFileName against a strict allowlist regex (e.g., /^[A-Za-z0-9._-]+\.cjs$/)
in the code that constructs hookCommand and reject or sanitize anything that
doesn't match, then safely quote or escape the path when composing hookCommand
(e.g., wrap the relative path in single quotes and escape contained single
quotes) so the final string cannot inject shell metacharacters before it is
passed to the Claude Code hook runner.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/installer/src/wizard/ide-config-generator.jspackages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js
| // Use relative path — works on all platforms, no $CLAUDE_PROJECT_DIR bugs | ||
| // (GH #6023/#5814), no fragile absolute Windows paths with escaped backslashes. | ||
| // Claude Code resolves relative paths from the project root (cwd). | ||
| const hookCommand = `node .claude/hooks/${hookFileName}`; | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# First, let's verify the file exists and check the content around lines 791-795
echo "=== Checking file existence and content ==="
wc -l packages/installer/src/wizard/ide-config-generator.js
echo -e "\n=== Content around lines 791-795 ==="
sed -n '785,805p' packages/installer/src/wizard/ide-config-generator.jsRepository: SynkraAI/aios-core
Length of output: 1069
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Search for hook filename filtering and validation
echo "=== Searching for hook file filtering and validation ==="
rg -n -B5 -A5 "hookFiles.*filter|hookFileName|\.cjs" packages/installer/src/wizard/ide-config-generator.js | head -100Repository: SynkraAI/aios-core
Length of output: 3110
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check what happens with hookCommand after it's created
echo "=== Searching for hookCommand usage ==="
rg -n -A10 "const hookCommand" packages/installer/src/wizard/ide-config-generator.jsRepository: SynkraAI/aios-core
Length of output: 614
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Search for hookCommand usage downstream
echo "=== Looking for hookCommand usage ==="
rg -n "hookCommand" packages/installer/src/wizard/ide-config-generator.jsRepository: SynkraAI/aios-core
Length of output: 203
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Get more context after line 794
echo "=== Content from line 794 to end of function ==="
sed -n '794,850p' packages/installer/src/wizard/ide-config-generator.jsRepository: SynkraAI/aios-core
Length of output: 1871
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check if this file uses shell execution functions and how
echo "=== Searching for shell execution patterns ==="
rg -n "exec|spawn|child_process|shell.*true" packages/installer/src/wizard/ide-config-generator.jsRepository: SynkraAI/aios-core
Length of output: 583
Escape and validate hook filenames before composing command
Line 794 interpolates hookFileName directly into a command string without escaping or validation. Although .cjs files are filtered by extension (line 757), this alone is insufficient to prevent shell injection. A filename containing spaces or shell metacharacters (e.g., hook$(whoami).cjs or hook; cmd.cjs) would pass the filter and be embedded in the command string. Even though hookCommand is stored as a string for later execution rather than directly executed here, the command is eventually passed to Claude Code's hook runner, where it may be executed in a shell context.
Harden by validating filenames against an allowlist pattern and safely quoting the path:
- const hookCommand = `node .claude/hooks/${hookFileName}`;
+ if (!/^[a-zA-Z0-9._-]+\.cjs$/.test(hookFileName)) {
+ continue;
+ }
+ const safeHookPath = JSON.stringify(path.posix.join('.claude', 'hooks', hookFileName));
+ const hookCommand = `node ${safeHookPath}`;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Use relative path — works on all platforms, no $CLAUDE_PROJECT_DIR bugs | |
| // (GH #6023/#5814), no fragile absolute Windows paths with escaped backslashes. | |
| // Claude Code resolves relative paths from the project root (cwd). | |
| const hookCommand = `node .claude/hooks/${hookFileName}`; | |
| // Use relative path — works on all platforms, no $CLAUDE_PROJECT_DIR bugs | |
| // (GH `#6023/`#5814), no fragile absolute Windows paths with escaped backslashes. | |
| // Claude Code resolves relative paths from the project root (cwd). | |
| if (!/^[a-zA-Z0-9._-]+\.cjs$/.test(hookFileName)) { | |
| continue; | |
| } | |
| const safeHookPath = JSON.stringify(path.posix.join('.claude', 'hooks', hookFileName)); | |
| const hookCommand = `node ${safeHookPath}`; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/installer/src/wizard/ide-config-generator.js` around lines 791 -
795, hookCommand currently interpolates hookFileName directly (const hookCommand
= `node .claude/hooks/${hookFileName}`), which allows filenames with spaces or
shell metacharacters to slip through; validate hookFileName against a strict
allowlist regex (e.g., /^[A-Za-z0-9._-]+\.cjs$/) in the code that constructs
hookCommand and reject or sanitize anything that doesn't match, then safely
quote or escape the path when composing hookCommand (e.g., wrap the relative
path in single quotes and escape contained single quotes) so the final string
cannot inject shell metacharacters before it is passed to the Claude Code hook
runner.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
Superseded by #551 which includes the complete hook fix (8 bugs resolved, not just the generator). |
Summary
node .claude/hooks/<file>) for hook commands insettings.local.jsontimeoutfrom hook config — Claude Code manages timeouts natively (default 60s); low overrides (10s) caused premature kills on Windows$CLAUDE_PROJECT_DIRbug GH #6023/#5814) since relative paths work cross-platformFiles changed
packages/installer/src/wizard/ide-config-generator.js— simplify hook command generationpackages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js— update assertionsTest plan
timeoutfieldnpx aios-core installgenerates correctsettings.local.jsonon Windowsnpx aios-core installgenerates correctsettings.local.jsonon macOS/Linux🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
Refactor
Tests