Skip to content

Commit a892ff1

Browse files
authored
fix: make Claude hook settings shell neutral (#671)
1 parent e83c2a5 commit a892ff1

5 files changed

Lines changed: 70 additions & 6 deletions

File tree

.claude/settings.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"hooks": [
66
{
77
"type": "command",
8-
"command": "node \"${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/synapse-wrapper.cjs\"",
8+
"command": "node .claude/hooks/synapse-wrapper.cjs",
99
"timeout": 10
1010
}
1111
]
@@ -16,7 +16,7 @@
1616
"hooks": [
1717
{
1818
"type": "command",
19-
"command": "node \"${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/precompact-wrapper.cjs\"",
19+
"command": "node .claude/hooks/precompact-wrapper.cjs",
2020
"timeout": 10
2121
}
2222
]
@@ -28,7 +28,7 @@
2828
"hooks": [
2929
{
3030
"type": "command",
31-
"command": "node \"${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/enforce-git-push-authority.cjs\"",
31+
"command": "node .claude/hooks/enforce-git-push-authority.cjs",
3232
"timeout": 10
3333
}
3434
]
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# STORY-123.16: Tornar comandos de hooks Claude shell-neutral
2+
3+
## Status
4+
5+
Done
6+
7+
## Story
8+
9+
Como mantenedor do AIOX Core em Windows e Unix, quero que o `.claude/settings.json` versionado registre hooks com caminhos relativos neutros de shell, para que o Claude Code não dependa de expansão POSIX como `${CLAUDE_PROJECT_DIR:-.}` ao executar os hooks do próprio repositório.
10+
11+
## Acceptance Criteria
12+
13+
- [x] AC1. Os comandos versionados de `UserPromptSubmit`, `PreCompact` e `PreToolUse` não usam `CLAUDE_PROJECT_DIR` nem expansão `${...}`.
14+
- [x] AC2. Os hooks continuam apontando para os wrappers commitados em `.claude/hooks/`.
15+
- [x] AC3. A governança de `PreToolUse` continua registrando o matcher `Bash`.
16+
- [x] AC4. Há teste automatizado impedindo regressão para sintaxe dependente de shell POSIX.
17+
18+
## Tasks
19+
20+
- [x] Atualizar `.claude/settings.json`.
21+
- [x] Adicionar teste de comando shell-neutral em `tests/claude/subagent-governance.test.js`.
22+
- [x] Rodar validação focada de governança Claude.
23+
24+
## Dev Notes
25+
26+
- Este é o resíduo limpo do PR #551: o installer já usa caminho absoluto em Windows porque `$CLAUDE_PROJECT_DIR` é problemático nessa plataforma, mas o settings commitado ainda usava `${CLAUDE_PROJECT_DIR:-.}`.
27+
- Mantivemos os wrappers atuais (`synapse-wrapper.cjs` e `precompact-wrapper.cjs`) em vez de voltar para os hooks diretos do PR antigo.
28+
29+
## Validation
30+
31+
- `npm test -- tests/claude/subagent-governance.test.js --runInBand --forceExit` -> PASS.
32+
- `git diff --check` -> PASS.
33+
- `npm run validate:semantic-lint` -> PASS.
34+
- `npm run validate:manifest` -> PASS.
35+
- `npm run validate:publish` -> PASS.
36+
- `npm run lint -- --quiet` -> PASS.
37+
- `npm run typecheck` -> PASS.
38+
- `npm run test:ci` -> PASS, 315 suites / 7.847 tests, 149 skipped.
39+
40+
## File List
41+
42+
- `.claude/settings.json`
43+
- `tests/claude/subagent-governance.test.js`
44+
- `docs/stories/epic-123/STORY-123.16-claude-hook-settings-windows-path.md`

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@aiox-squads/core",
3-
"version": "5.1.10",
3+
"version": "5.1.11",
44
"description": "Synkra AIOX: AI-Orchestrated System for Full Stack Development - Core Framework",
55
"bin": {
66
"aiox": "bin/aiox.js",

tests/claude/subagent-governance.test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,26 @@ describe('Claude native subagent governance', () => {
6969
expect(preToolUse.some(entry => entry.matcher === 'Bash')).toBe(true);
7070
});
7171

72+
it('uses shell-neutral project hook commands in committed Claude settings', () => {
73+
const settings = JSON.parse(fs.readFileSync(path.join(repoRoot, '.claude', 'settings.json'), 'utf8'));
74+
const commands = Object.values(settings.hooks || {})
75+
.flat()
76+
.flatMap(entry => entry.hooks || [])
77+
.map(hook => hook.command);
78+
79+
expect(commands).toEqual(expect.arrayContaining([
80+
'node .claude/hooks/synapse-wrapper.cjs',
81+
'node .claude/hooks/precompact-wrapper.cjs',
82+
'node .claude/hooks/enforce-git-push-authority.cjs',
83+
]));
84+
85+
for (const command of commands) {
86+
expect(command).not.toContain('CLAUDE_PROJECT_DIR');
87+
expect(command).not.toContain('${');
88+
expect(command).toMatch(/^node \.claude\/hooks\/[-a-z]+\.cjs$/);
89+
}
90+
});
91+
7292
it('blocks remote GitHub operations outside devops and allows devops-tagged commands', () => {
7393
const blockedCommands = [
7494
'git push origin main',

0 commit comments

Comments
 (0)