Skip to content
Merged
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
6 changes: 3 additions & 3 deletions .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"hooks": [
{
"type": "command",
"command": "node \"${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/synapse-wrapper.cjs\"",
"command": "node .claude/hooks/synapse-wrapper.cjs",
"timeout": 10
}
]
Expand All @@ -16,7 +16,7 @@
"hooks": [
{
"type": "command",
"command": "node \"${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/precompact-wrapper.cjs\"",
"command": "node .claude/hooks/precompact-wrapper.cjs",
"timeout": 10
}
]
Expand All @@ -28,7 +28,7 @@
"hooks": [
{
"type": "command",
"command": "node \"${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/enforce-git-push-authority.cjs\"",
"command": "node .claude/hooks/enforce-git-push-authority.cjs",
"timeout": 10
}
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# STORY-123.16: Tornar comandos de hooks Claude shell-neutral

## Status

Done

## Story

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.

## Acceptance Criteria

- [x] AC1. Os comandos versionados de `UserPromptSubmit`, `PreCompact` e `PreToolUse` não usam `CLAUDE_PROJECT_DIR` nem expansão `${...}`.
- [x] AC2. Os hooks continuam apontando para os wrappers commitados em `.claude/hooks/`.
- [x] AC3. A governança de `PreToolUse` continua registrando o matcher `Bash`.
- [x] AC4. Há teste automatizado impedindo regressão para sintaxe dependente de shell POSIX.

## Tasks

- [x] Atualizar `.claude/settings.json`.
- [x] Adicionar teste de comando shell-neutral em `tests/claude/subagent-governance.test.js`.
- [x] Rodar validação focada de governança Claude.

## Dev Notes

- 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:-.}`.
- Mantivemos os wrappers atuais (`synapse-wrapper.cjs` e `precompact-wrapper.cjs`) em vez de voltar para os hooks diretos do PR antigo.

## Validation

- `npm test -- tests/claude/subagent-governance.test.js --runInBand --forceExit` -> PASS.
- `git diff --check` -> PASS.
- `npm run validate:semantic-lint` -> PASS.
- `npm run validate:manifest` -> PASS.
- `npm run validate:publish` -> PASS.
- `npm run lint -- --quiet` -> PASS.
- `npm run typecheck` -> PASS.
- `npm run test:ci` -> PASS, 315 suites / 7.847 tests, 149 skipped.

## File List

- `.claude/settings.json`
- `tests/claude/subagent-governance.test.js`
- `docs/stories/epic-123/STORY-123.16-claude-hook-settings-windows-path.md`
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@aiox-squads/core",
"version": "5.1.10",
"version": "5.1.11",
"description": "Synkra AIOX: AI-Orchestrated System for Full Stack Development - Core Framework",
"bin": {
"aiox": "bin/aiox.js",
Expand Down
20 changes: 20 additions & 0 deletions tests/claude/subagent-governance.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,26 @@ describe('Claude native subagent governance', () => {
expect(preToolUse.some(entry => entry.matcher === 'Bash')).toBe(true);
});

it('uses shell-neutral project hook commands in committed Claude settings', () => {
const settings = JSON.parse(fs.readFileSync(path.join(repoRoot, '.claude', 'settings.json'), 'utf8'));
const commands = Object.values(settings.hooks || {})
.flat()
.flatMap(entry => entry.hooks || [])
.map(hook => hook.command);

expect(commands).toEqual(expect.arrayContaining([
'node .claude/hooks/synapse-wrapper.cjs',
'node .claude/hooks/precompact-wrapper.cjs',
'node .claude/hooks/enforce-git-push-authority.cjs',
]));

for (const command of commands) {
expect(command).not.toContain('CLAUDE_PROJECT_DIR');
expect(command).not.toContain('${');
expect(command).toMatch(/^node \.claude\/hooks\/[-a-z]+\.cjs$/);
}
});

it('blocks remote GitHub operations outside devops and allows devops-tagged commands', () => {
const blockedCommands = [
'git push origin main',
Expand Down
Loading