-
-
Notifications
You must be signed in to change notification settings - Fork 873
fix(installer): instalação condicional de hooks por tier (#544) #597
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -652,9 +652,29 @@ function showSuccessSummary(result) { | |||||||||||||||||||||||||||||||||||
| console.log(' 4. Use * commands to interact with agents\n'); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||
| * Hooks disponíveis para todos os tiers (free + pro) | ||||||||||||||||||||||||||||||||||||
| * @type {string[]} | ||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||
| const HOOKS_FREE = [ | ||||||||||||||||||||||||||||||||||||
| 'synapse-engine.cjs', | ||||||||||||||||||||||||||||||||||||
| 'synapse-wrapper.cjs', | ||||||||||||||||||||||||||||||||||||
| 'precompact-wrapper.cjs', | ||||||||||||||||||||||||||||||||||||
| 'README.md', | ||||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||
| * Hooks exclusivos do tier pro (requerem aios-pro) | ||||||||||||||||||||||||||||||||||||
| * @type {string[]} | ||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||
| const HOOKS_PRO_ONLY = [ | ||||||||||||||||||||||||||||||||||||
| 'precompact-session-digest.cjs', | ||||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||
| * BUG-3 fix (INS-1): Copy .claude/hooks/ folder during installation | ||||||||||||||||||||||||||||||||||||
| * Only copies JS hooks that work without external dependencies (Python, etc.) | ||||||||||||||||||||||||||||||||||||
| * Pro-only hooks (precompact-session-digest) are skipped when pro/ is unavailable (#544) | ||||||||||||||||||||||||||||||||||||
| * @param {string} projectRoot - Project root directory | ||||||||||||||||||||||||||||||||||||
| * @returns {Promise<string[]>} List of copied files | ||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||
|
|
@@ -674,13 +694,12 @@ async function copyClaudeHooksFolder(projectRoot) { | |||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| await fs.ensureDir(targetDir); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Only copy JS hooks that work standalone (no Python/shell deps) | ||||||||||||||||||||||||||||||||||||
| const HOOKS_TO_COPY = [ | ||||||||||||||||||||||||||||||||||||
| 'synapse-engine.cjs', | ||||||||||||||||||||||||||||||||||||
| 'code-intel-pretool.cjs', | ||||||||||||||||||||||||||||||||||||
| 'precompact-session-digest.cjs', | ||||||||||||||||||||||||||||||||||||
| 'README.md', | ||||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||||
| // Detecta se pro/ está disponível para decidir quais hooks copiar (#544) | ||||||||||||||||||||||||||||||||||||
| const { isProAvailable } = require('../../../../bin/utils/pro-detector'); | ||||||||||||||||||||||||||||||||||||
| const isPro = isProAvailable(); | ||||||||||||||||||||||||||||||||||||
| const HOOKS_TO_COPY = isPro | ||||||||||||||||||||||||||||||||||||
| ? [...HOOKS_FREE, ...HOOKS_PRO_ONLY] | ||||||||||||||||||||||||||||||||||||
| : HOOKS_FREE; | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+697
to
+702
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Guard pro detection failures and default to free hooks. If 💡 Proposed fix- const { isProAvailable } = require('../../../../bin/utils/pro-detector');
- const isPro = isProAvailable();
+ let isPro = false;
+ try {
+ const { isProAvailable } = require('../../../../bin/utils/pro-detector');
+ isPro = Boolean(isProAvailable());
+ } catch (_) {
+ isPro = false;
+ }
const HOOKS_TO_COPY = isPro
? [...HOOKS_FREE, ...HOOKS_PRO_ONLY]
: HOOKS_FREE;As per coding guidelines 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const files = await fs.readdir(sourceDir); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| /** | ||
| * Testes para instalação condicional de hooks por tier (#544) | ||
| * | ||
| * Valida que hooks pro-only não são copiados quando pro/ não está disponível. | ||
| * | ||
| * @see packages/installer/src/wizard/ide-config-generator.js | ||
| * @issue #544 | ||
| */ | ||
|
|
||
| 'use strict'; | ||
|
|
||
| const path = require('path'); | ||
| const fs = require('fs-extra'); | ||
| const os = require('os'); | ||
|
|
||
| // O módulo sob teste | ||
| const { | ||
| copyClaudeHooksFolder, | ||
| } = require('../../packages/installer/src/wizard/ide-config-generator'); | ||
|
|
||
| // Mock do pro-detector | ||
| jest.mock('../../bin/utils/pro-detector'); | ||
| const proDetector = require('../../bin/utils/pro-detector'); | ||
|
|
||
| function makeTempDir() { | ||
| return fs.mkdtempSync(path.join(os.tmpdir(), 'hooks-test-')); | ||
| } | ||
|
|
||
| describe('copyClaudeHooksFolder — tier-aware (#544)', () => { | ||
| let tmpDir; | ||
|
|
||
| beforeEach(() => { | ||
| tmpDir = makeTempDir(); | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| fs.rmSync(tmpDir, { recursive: true, force: true }); | ||
| }); | ||
|
|
||
| it('deve copiar apenas hooks free quando pro não está disponível', async () => { | ||
| proDetector.isProAvailable.mockReturnValue(false); | ||
|
|
||
| const copiedFiles = await copyClaudeHooksFolder(tmpDir); | ||
| const fileNames = copiedFiles.map((f) => path.basename(f)); | ||
|
|
||
| expect(fileNames).toContain('synapse-engine.cjs'); | ||
| expect(fileNames).toContain('README.md'); | ||
| expect(fileNames).not.toContain('precompact-session-digest.cjs'); | ||
| }); | ||
|
|
||
| it('deve copiar todos os hooks incluindo pro quando pro está disponível', async () => { | ||
| proDetector.isProAvailable.mockReturnValue(true); | ||
|
|
||
| const copiedFiles = await copyClaudeHooksFolder(tmpDir); | ||
| const fileNames = copiedFiles.map((f) => path.basename(f)); | ||
|
|
||
| expect(fileNames).toContain('synapse-engine.cjs'); | ||
| expect(fileNames).toContain('precompact-session-digest.cjs'); | ||
| expect(fileNames).toContain('README.md'); | ||
| }); | ||
|
|
||
| it('deve retornar array vazio quando source === target (framework-dev)', async () => { | ||
| proDetector.isProAvailable.mockReturnValue(false); | ||
|
|
||
| // Aponta projectRoot para o próprio framework root | ||
| const frameworkRoot = path.resolve(__dirname, '..', '..'); | ||
| const result = await copyClaudeHooksFolder(frameworkRoot); | ||
| expect(result).toEqual([]); | ||
| }); | ||
|
|
||
| it('deve sempre copiar README.md independente do tier', async () => { | ||
| proDetector.isProAvailable.mockReturnValue(false); | ||
|
|
||
| const copiedFiles = await copyClaudeHooksFolder(tmpDir); | ||
| const fileNames = copiedFiles.map((f) => path.basename(f)); | ||
|
|
||
| expect(fileNames).toContain('README.md'); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
code-intel-pretool.cjsis never copied, so its mapped hook can’t be installed.HOOK_EVENT_MAPstill definescode-intel-pretool.cjs, but the new tier allowlists omit it entirely. That silently drops PreToolUse coverage in installed projects.💡 Proposed fix
const HOOKS_FREE = [ 'synapse-engine.cjs', + 'code-intel-pretool.cjs', 'synapse-wrapper.cjs', 'precompact-wrapper.cjs', 'README.md', ];Also applies to: 670-672
🤖 Prompt for AI Agents