Skip to content

feat(installer): conditionally install hooks based on free/pro tier selection #544

@riaworks

Description

@riaworks

Problem

The installer copies all hook files to every project regardless of tier:

// ide-config-generator.js:678
const HOOKS_TO_COPY = [
  'synapse-engine.cjs',
  'code-intel-pretool.cjs',
  'precompact-session-digest.cjs',  // ← only useful with aios-pro
  'README.md',
];

precompact-session-digest.cjs is a PreCompact hook that:

  1. Detects if aios-pro is installed
  2. If yes → extracts a session digest before context compaction
  3. If no → silent no-op (aios-pro not available, skipping)

For free/community users, this hook:

  • Is always copied (unnecessary file)
  • Is always registered in settings.local.json (unnecessary entry)
  • Always results in a no-op (wasted process spawn on every compact)

Additionally, the hook is written as a module export (module.exports = async (context) => {...}) but registered as a command hook in settings.local.json. Command hooks must read JSON from stdin and write JSON to stdout — this hook does neither, causing errors when invoked as a command.

Proposed Solution

1. Tier-aware hook installation

During the wizard install step (where user selects free vs pro), conditionally select which hooks to copy:

const HOOKS_FREE = [
  'synapse-engine.cjs',
  'code-intel-pretool.cjs',
  'README.md',
];

const HOOKS_PRO = [
  ...HOOKS_FREE,
  'precompact-session-digest.cjs',
];

const HOOKS_TO_COPY = wizardState.tier === 'pro' ? HOOKS_PRO : HOOKS_FREE;

2. Rewrite precompact hook as command hook

precompact-session-digest.cjs currently exports a function (module pattern). For it to work as a Claude Code command hook registered in settings.local.json, it needs a stdin/stdout wrapper similar to synapse-engine.cjs:

// Read JSON from stdin
const input = await readStdin();
// Call the digest logic
await onPreCompact(input);
// Write result to stdout
process.stdout.write(JSON.stringify({ hookSpecificOutput: { ... } }));

Without this rewrite, even pro users will get errors when the hook is invoked as a command.

3. Dynamic registration in settings.local.json

createClaudeSettingsLocal() already reads from the hooks directory dynamically, so as long as step 1 doesn't copy the file for free users, it won't be registered. No change needed here.

Files to Modify

File Change
packages/installer/src/wizard/ide-config-generator.js Tier-aware HOOKS_TO_COPY
.claude/hooks/precompact-session-digest.cjs Rewrite as command hook (stdin/stdout)
.aios-core/hooks/unified/runners/precompact-runner.js May need adapter for command hook pattern

Context

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: cliCLI tools (bin/, packages/aios-pro-cli/)area: installerInstaller and setup (packages/installer/)area: proPro features (pro/)area: synapseSYNAPSE context enginestatus: needs-triageAwaiting initial triage

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions