create-merlin-brain 3.11.0 → 3.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/bin/install.cjs +156 -32
  2. package/bin/runtime-adapters.cjs +396 -0
  3. package/dist/server/api/types.d.ts +7 -0
  4. package/dist/server/api/types.d.ts.map +1 -1
  5. package/dist/server/cost/tracker.d.ts +38 -2
  6. package/dist/server/cost/tracker.d.ts.map +1 -1
  7. package/dist/server/cost/tracker.js +87 -15
  8. package/dist/server/cost/tracker.js.map +1 -1
  9. package/dist/server/server.d.ts.map +1 -1
  10. package/dist/server/server.js +74 -30
  11. package/dist/server/server.js.map +1 -1
  12. package/dist/server/tools/__tests__/augmentation.test.d.ts +8 -0
  13. package/dist/server/tools/__tests__/augmentation.test.d.ts.map +1 -0
  14. package/dist/server/tools/__tests__/augmentation.test.js +76 -0
  15. package/dist/server/tools/__tests__/augmentation.test.js.map +1 -0
  16. package/dist/server/tools/__tests__/route-helpers.test.d.ts +5 -0
  17. package/dist/server/tools/__tests__/route-helpers.test.d.ts.map +1 -0
  18. package/dist/server/tools/__tests__/route-helpers.test.js +49 -0
  19. package/dist/server/tools/__tests__/route-helpers.test.js.map +1 -0
  20. package/dist/server/tools/adaptive.js +1 -1
  21. package/dist/server/tools/adaptive.js.map +1 -1
  22. package/dist/server/tools/agent-spawn.d.ts +25 -0
  23. package/dist/server/tools/agent-spawn.d.ts.map +1 -0
  24. package/dist/server/tools/agent-spawn.js +95 -0
  25. package/dist/server/tools/agent-spawn.js.map +1 -0
  26. package/dist/server/tools/agents-index.js +3 -3
  27. package/dist/server/tools/agents-index.js.map +1 -1
  28. package/dist/server/tools/agents.js +5 -5
  29. package/dist/server/tools/agents.js.map +1 -1
  30. package/dist/server/tools/augmentation.d.ts +45 -0
  31. package/dist/server/tools/augmentation.d.ts.map +1 -0
  32. package/dist/server/tools/augmentation.js +167 -0
  33. package/dist/server/tools/augmentation.js.map +1 -0
  34. package/dist/server/tools/behaviors.js +4 -4
  35. package/dist/server/tools/behaviors.js.map +1 -1
  36. package/dist/server/tools/context.js +7 -7
  37. package/dist/server/tools/context.js.map +1 -1
  38. package/dist/server/tools/cost.d.ts +3 -1
  39. package/dist/server/tools/cost.d.ts.map +1 -1
  40. package/dist/server/tools/cost.js +66 -13
  41. package/dist/server/tools/cost.js.map +1 -1
  42. package/dist/server/tools/discoveries.js +6 -6
  43. package/dist/server/tools/discoveries.js.map +1 -1
  44. package/dist/server/tools/index.d.ts +4 -0
  45. package/dist/server/tools/index.d.ts.map +1 -1
  46. package/dist/server/tools/index.js +4 -0
  47. package/dist/server/tools/index.js.map +1 -1
  48. package/dist/server/tools/learning.d.ts +12 -0
  49. package/dist/server/tools/learning.d.ts.map +1 -0
  50. package/dist/server/tools/learning.js +269 -0
  51. package/dist/server/tools/learning.js.map +1 -0
  52. package/dist/server/tools/project.js +7 -7
  53. package/dist/server/tools/project.js.map +1 -1
  54. package/dist/server/tools/promote.d.ts +11 -0
  55. package/dist/server/tools/promote.d.ts.map +1 -0
  56. package/dist/server/tools/promote.js +315 -0
  57. package/dist/server/tools/promote.js.map +1 -0
  58. package/dist/server/tools/route-helpers.d.ts +45 -0
  59. package/dist/server/tools/route-helpers.d.ts.map +1 -0
  60. package/dist/server/tools/route-helpers.js +93 -0
  61. package/dist/server/tools/route-helpers.js.map +1 -0
  62. package/dist/server/tools/route.d.ts +4 -3
  63. package/dist/server/tools/route.d.ts.map +1 -1
  64. package/dist/server/tools/route.js +80 -284
  65. package/dist/server/tools/route.js.map +1 -1
  66. package/dist/server/tools/session-restore.d.ts +18 -0
  67. package/dist/server/tools/session-restore.d.ts.map +1 -0
  68. package/dist/server/tools/session-restore.js +154 -0
  69. package/dist/server/tools/session-restore.js.map +1 -0
  70. package/dist/server/tools/session-search.d.ts +16 -0
  71. package/dist/server/tools/session-search.d.ts.map +1 -0
  72. package/dist/server/tools/session-search.js +240 -0
  73. package/dist/server/tools/session-search.js.map +1 -0
  74. package/dist/server/tools/sights-index.js +2 -2
  75. package/dist/server/tools/sights-index.js.map +1 -1
  76. package/dist/server/tools/smart-route.d.ts.map +1 -1
  77. package/dist/server/tools/smart-route.js +4 -5
  78. package/dist/server/tools/smart-route.js.map +1 -1
  79. package/dist/server/tools/verification.js +1 -1
  80. package/dist/server/tools/verification.js.map +1 -1
  81. package/files/agents/code-organization-supervisor.md +1 -0
  82. package/files/agents/context-guardian.md +1 -0
  83. package/files/agents/docs-keeper.md +1 -0
  84. package/files/agents/dry-refactor.md +1 -0
  85. package/files/agents/elite-code-refactorer.md +1 -0
  86. package/files/agents/hardening-guard.md +1 -0
  87. package/files/agents/implementation-dev.md +1 -0
  88. package/files/agents/merlin-access-control-reviewer.md +248 -0
  89. package/files/agents/merlin-codebase-mapper.md +1 -1
  90. package/files/agents/merlin-dependency-auditor.md +216 -0
  91. package/files/agents/merlin-executor.md +1 -0
  92. package/files/agents/merlin-input-validator.md +247 -0
  93. package/files/agents/merlin-reviewer.md +1 -0
  94. package/files/agents/merlin-sast-reviewer.md +182 -0
  95. package/files/agents/merlin-secret-scanner.md +203 -0
  96. package/files/agents/tests-qa.md +1 -0
  97. package/files/commands/merlin/execute-phase.md +94 -197
  98. package/files/commands/merlin/execute-plan.md +116 -180
  99. package/files/commands/merlin/health.md +385 -0
  100. package/files/commands/merlin/loop-recipes.md +93 -36
  101. package/files/commands/merlin/optimize-prompts.md +158 -0
  102. package/files/commands/merlin/profiles.md +215 -0
  103. package/files/commands/merlin/promote.md +176 -0
  104. package/files/commands/merlin/quick.md +229 -0
  105. package/files/commands/merlin/resume-work.md +27 -1
  106. package/files/commands/merlin/route.md +43 -1
  107. package/files/commands/merlin/sandbox.md +359 -0
  108. package/files/commands/merlin/usage.md +55 -0
  109. package/files/docker/Dockerfile.merlin +20 -0
  110. package/files/docker/docker-compose.merlin.yml +23 -0
  111. package/files/hook-templates/auto-commit.sh +64 -0
  112. package/files/hook-templates/auto-format.sh +95 -0
  113. package/files/hook-templates/auto-test.sh +117 -0
  114. package/files/hook-templates/branch-protection.sh +72 -0
  115. package/files/hook-templates/changelog-reminder.sh +76 -0
  116. package/files/hook-templates/complexity-check.sh +112 -0
  117. package/files/hook-templates/import-audit.sh +83 -0
  118. package/files/hook-templates/license-header.sh +84 -0
  119. package/files/hook-templates/pr-description.sh +100 -0
  120. package/files/hook-templates/todo-tracker.sh +80 -0
  121. package/files/hooks/check-file-size.sh +17 -4
  122. package/files/hooks/config-change.sh +44 -16
  123. package/files/hooks/instructions-loaded.sh +22 -5
  124. package/files/hooks/notify-desktop.sh +157 -0
  125. package/files/hooks/notify-webhook.sh +141 -0
  126. package/files/hooks/pre-edit-sights-check.sh +76 -9
  127. package/files/hooks/security-scanner.sh +153 -0
  128. package/files/hooks/session-end-memory-sync.sh +97 -0
  129. package/files/hooks/session-end.sh +274 -1
  130. package/files/hooks/session-start.sh +19 -6
  131. package/files/hooks/smart-approve.sh +270 -0
  132. package/files/hooks/teammate-idle-verify.sh +87 -12
  133. package/files/hooks/worktree-create.sh +20 -3
  134. package/files/hooks/worktree-remove.sh +21 -3
  135. package/files/merlin/references/plan-format.md +37 -9
  136. package/files/merlin/sandbox.json +9 -0
  137. package/files/merlin/security.json +11 -0
  138. package/files/merlin/templates/ci/docs-update.yml +81 -0
  139. package/files/merlin/templates/ci/pr-review.yml +50 -0
  140. package/files/merlin/templates/ci/security-audit.yml +74 -0
  141. package/files/merlin/templates/config.json +9 -1
  142. package/files/rules/api-rules.md +30 -0
  143. package/files/rules/frontend-rules.md +25 -0
  144. package/files/rules/hooks-rules.md +36 -0
  145. package/files/rules/mcp-rules.md +30 -0
  146. package/files/rules/worker-rules.md +29 -0
  147. package/package.json +5 -2
package/bin/install.cjs CHANGED
@@ -11,6 +11,11 @@
11
11
  const isServeMode = process.argv.includes('serve');
12
12
  const isInjectMode = process.argv.includes('inject-headers');
13
13
 
14
+ // --runtime flag: 'all' | 'claude' | 'codex' | 'opencode' | 'gemini'
15
+ // Default: 'all' (configure all detected runtimes)
16
+ const runtimeFlagIdx = process.argv.indexOf('--runtime');
17
+ const RUNTIME_FLAG = runtimeFlagIdx !== -1 ? (process.argv[runtimeFlagIdx + 1] || 'all') : 'all';
18
+
14
19
  // =============================================================================
15
20
  // MODE: inject-headers - Add Merlin reminder to CLAUDE.md files
16
21
  // =============================================================================
@@ -101,12 +106,14 @@ const fs = require('fs');
101
106
  const path = require('path');
102
107
  const os = require('os');
103
108
  const readline = require('readline');
109
+ const { detectRuntimes, configureRuntimes } = require('./runtime-adapters.cjs');
104
110
 
105
111
  const CLAUDE_DIR = path.join(os.homedir(), '.claude');
106
112
  const MERLIN_DIR = path.join(CLAUDE_DIR, 'merlin');
107
113
  const AGENTS_DIR = path.join(CLAUDE_DIR, 'agents');
108
114
  const COMMANDS_DIR = path.join(CLAUDE_DIR, 'commands', 'merlin');
109
115
  const LOOP_DIR = path.join(CLAUDE_DIR, 'loop');
116
+ const RULES_DIR = path.join(CLAUDE_DIR, 'rules');
110
117
 
111
118
  const colors = {
112
119
  reset: '\x1b[0m',
@@ -138,7 +145,7 @@ function logError(msg) {
138
145
  log(` ${colors.red}✗${colors.reset} ${msg}`);
139
146
  }
140
147
 
141
- // Minimum Claude Code version required (--agent flag support)
148
+ // Minimum Claude Code version required (MCP server support)
142
149
  const MIN_CLAUDE_VERSION = '2.0.0';
143
150
 
144
151
  function parseVersion(v) {
@@ -192,7 +199,7 @@ function ensureClaudeCode() {
192
199
  }
193
200
 
194
201
  // Needs update
195
- logWarn(`Claude Code v${currentVersion} is too old (need >= ${MIN_CLAUDE_VERSION} for --agent support)`);
202
+ logWarn(`Claude Code v${currentVersion} is too old (need >= ${MIN_CLAUDE_VERSION})`);
196
203
  log(` ${colors.cyan}Updating Claude Code...${colors.reset}`);
197
204
 
198
205
  try {
@@ -333,23 +340,17 @@ function setupShellIntegration() {
333
340
  } else {
334
341
  logWarn(`Unknown shell (${shell}), skipping shell setup`);
335
342
  log(` Add manually to your shell rc file:`);
336
- log(` ${colors.cyan}function claude() { command claude --agent merlin "$@"; }${colors.reset}`);
337
343
  log(` ${colors.cyan}alias cc='claude'${colors.reset}`);
338
344
  return false;
339
345
  }
340
346
 
341
- // Simple Merlin shell integration - just wrap claude with merlin agent
347
+ // Merlin shell integration - shortcut alias and loop command
342
348
  const merlinBlock = `
343
349
  # ══════════════════════════════════════════════════════════════
344
350
  # Merlin Brain - The AI Brain for Claude Code
345
351
  # https://merlin.build
346
352
  # ══════════════════════════════════════════════════════════════
347
353
 
348
- # Simple claude wrapper - run with merlin agent
349
- claude() {
350
- command claude --agent merlin "$@"
351
- }
352
-
353
354
  # Shortcut alias
354
355
  alias cc="claude"
355
356
 
@@ -380,11 +381,17 @@ merlin-loop() {
380
381
  fs.writeFileSync(rcFile, rcContent);
381
382
  logSuccess('Updating existing Merlin shell integration');
382
383
  }
384
+
385
+ // Remove broken claude() wrapper from older installs (--agent flag doesn't exist)
386
+ if (rcContent.includes('command claude --agent')) {
387
+ rcContent = rcContent.replace(/\n?# Simple claude wrapper.*\nclaude\(\) \{\n\s*command claude --agent.*\n\}\n?/g, '\n');
388
+ fs.writeFileSync(rcFile, rcContent);
389
+ logSuccess('Removed broken claude() wrapper (--agent flag is not valid)');
390
+ }
383
391
  }
384
392
 
385
393
  // Add new Merlin integration block
386
394
  fs.appendFileSync(rcFile, merlinBlock);
387
- logSuccess(`Configured 'claude' command to use Merlin`);
388
395
  logSuccess(`Added 'cc' shortcut`);
389
396
  logSuccess(`Version check enabled (run /merlin:update to update)`);
390
397
  return true;
@@ -838,7 +845,7 @@ async function install() {
838
845
  }
839
846
 
840
847
  // Step 0: Clean up legacy GSD/ccwiki artifacts
841
- logStep('0/11', 'Cleaning up legacy installations...');
848
+ logStep('0/13', 'Cleaning up legacy installations...');
842
849
  const cleaned = cleanupLegacy();
843
850
  if (cleaned.length > 0) {
844
851
  for (const item of cleaned) {
@@ -849,11 +856,24 @@ async function install() {
849
856
  }
850
857
 
851
858
  // Step 1: Ensure Claude Code is installed and up to date
852
- logStep('1/11', 'Checking Claude Code...');
859
+ logStep('1/13', 'Checking Claude Code...');
853
860
  const claudeCheck = ensureClaudeCode();
854
861
 
855
- // Step 2: Install globally for instant startup across all terminals
856
- logStep('2/11', 'Installing globally (fast startup for all terminals)...');
862
+ // Step 2: Detect runtimes
863
+ logStep('2/13', 'Detecting runtimes...');
864
+ const detectedRuntimes = detectRuntimes();
865
+ log(` ${colors.green}✅${colors.reset} Claude Code (primary)`);
866
+ for (const rt of detectedRuntimes) {
867
+ const icon = rt.found ? `${colors.green}✅${colors.reset}` : `${colors.yellow}⬚${colors.reset}`;
868
+ const suffix = rt.found ? '' : ' (not found)';
869
+ log(` ${icon} ${rt.label}${suffix}`);
870
+ }
871
+ if (RUNTIME_FLAG === 'claude') {
872
+ log(` ${colors.yellow}--runtime claude:${colors.reset} other runtimes will not be configured`);
873
+ }
874
+
875
+ // Step 3: Install globally for instant startup across all terminals
876
+ logStep('3/13', 'Installing globally (fast startup for all terminals)...');
857
877
  try {
858
878
  const { execSync } = require('child_process');
859
879
  // Check if already installed globally and up-to-date
@@ -893,16 +913,16 @@ async function install() {
893
913
  useGlobalBinary = false;
894
914
  }
895
915
 
896
- // Step 3: Create directories
897
- logStep('3/11', 'Creating directories...');
916
+ // Step 4: Create directories
917
+ logStep('4/13', 'Creating directories...');
898
918
  ensureDir(CLAUDE_DIR);
899
919
  ensureDir(MERLIN_DIR);
900
920
  ensureDir(AGENTS_DIR);
901
921
  ensureDir(COMMANDS_DIR);
902
922
  logSuccess('Directories created');
903
923
 
904
- // Step 4: Install Merlin core (workflows, references, templates)
905
- logStep('4/11', 'Installing Merlin workflows...');
924
+ // Step 5: Install Merlin core (workflows, references, templates)
925
+ logStep('5/13', 'Installing Merlin workflows...');
906
926
  const merlinSrc = path.join(filesDir, 'merlin');
907
927
  if (fs.existsSync(merlinSrc)) {
908
928
  const count = copyDirRecursive(merlinSrc, MERLIN_DIR);
@@ -914,8 +934,8 @@ async function install() {
914
934
  logWarn('Merlin workflows not found in package');
915
935
  }
916
936
 
917
- // Step 5: Install agents (tiered)
918
- logStep('5/11', 'Installing Merlin agents...');
937
+ // Step 6: Install agents (tiered)
938
+ logStep('6/13', 'Installing Merlin agents...');
919
939
  const agentsSrc = path.join(filesDir, 'agents');
920
940
  if (fs.existsSync(agentsSrc)) {
921
941
  // Load agent manifest for tiered display
@@ -942,8 +962,32 @@ async function install() {
942
962
  logWarn('Agents not found in package');
943
963
  }
944
964
 
945
- // Step 6: Install commands
946
- logStep('6/11', 'Installing /merlin:* commands...');
965
+ // Step 7: Install path-scoped rules
966
+ logStep('7/13', 'Installing path-scoped rules...');
967
+ const rulesSrc = path.join(filesDir, 'rules');
968
+ if (fs.existsSync(rulesSrc)) {
969
+ ensureDir(RULES_DIR);
970
+ const ruleFiles = fs.readdirSync(rulesSrc).filter(f => f.endsWith('.md'));
971
+ let installedCount = 0;
972
+ let skippedCount = 0;
973
+ for (const ruleFile of ruleFiles) {
974
+ const destPath = path.join(RULES_DIR, ruleFile);
975
+ // Never overwrite existing user rules — they may have been customized
976
+ if (fs.existsSync(destPath)) {
977
+ skippedCount++;
978
+ } else {
979
+ fs.copyFileSync(path.join(rulesSrc, ruleFile), destPath);
980
+ installedCount++;
981
+ }
982
+ }
983
+ if (installedCount > 0) logSuccess(`Installed ${installedCount} path-scoped rule files`);
984
+ if (skippedCount > 0) logSuccess(`Skipped ${skippedCount} existing rule files (user customizations preserved)`);
985
+ } else {
986
+ logWarn('Rules not found in package');
987
+ }
988
+
989
+ // Step 8: Install commands
990
+ logStep('8/13', 'Installing /merlin:* commands...');
947
991
  const commandsSrc = path.join(filesDir, 'commands', 'merlin');
948
992
  if (fs.existsSync(commandsSrc)) {
949
993
  const count = copyDirRecursive(commandsSrc, COMMANDS_DIR);
@@ -952,8 +996,8 @@ async function install() {
952
996
  logWarn('Commands not found in package');
953
997
  }
954
998
 
955
- // Step 7: Install CLAUDE.md
956
- logStep('7/11', 'Configuring Claude Code...');
999
+ // Step 9: Install CLAUDE.md
1000
+ logStep('9/13', 'Configuring Claude Code...');
957
1001
  const claudeMdSrc = path.join(filesDir, 'CLAUDE.md');
958
1002
  const claudeMdDest = path.join(CLAUDE_DIR, 'CLAUDE.md');
959
1003
 
@@ -964,12 +1008,12 @@ async function install() {
964
1008
  logSuccess('Installed CLAUDE.md (Merlin instructions)');
965
1009
  }
966
1010
 
967
- // Step 8: Install Merlin Loop (legacy — kept for backward compatibility)
1011
+ // Step 10: Install Merlin Loop (legacy — kept for backward compatibility)
968
1012
  // NOTE: Claude Code now has a native /loop command that replaces these scripts.
969
1013
  // Use /merlin:loop-recipes in Claude Code for pre-built loop patterns.
970
1014
  // These scripts are still copied so existing users and terminal workflows
971
1015
  // (merlin-loop, merlin session) continue to work without interruption.
972
- logStep('8/11', 'Installing Merlin Loop (legacy scripts)...');
1016
+ logStep('10/13', 'Installing Merlin Loop (legacy scripts)...');
973
1017
  const loopSrc = path.join(filesDir, 'loop');
974
1018
  if (fs.existsSync(loopSrc)) {
975
1019
  ensureDir(LOOP_DIR);
@@ -996,12 +1040,13 @@ async function install() {
996
1040
  logSuccess(`Installed ${count} loop files`);
997
1041
  logSuccess(`Added 'merlin-loop' command`);
998
1042
  logSuccess(`Added 'merlin session' command (interactive orchestrator)`);
1043
+ logWarn(`Note: Custom loop scripts are deprecated. Use /loop with /merlin:loop-recipes instead.`);
999
1044
  } else {
1000
1045
  logWarn('Merlin Loop not found in package');
1001
1046
  }
1002
1047
 
1003
- // Step 9: Install Claude Code hooks
1004
- logStep('9/11', 'Installing Claude Code hooks...');
1048
+ // Step 11: Install Claude Code hooks
1049
+ logStep('11/13', 'Installing Claude Code hooks...');
1005
1050
  const HOOKS_DIR = path.join(CLAUDE_DIR, 'hooks');
1006
1051
  const hooksSrc = path.join(filesDir, 'hooks');
1007
1052
  if (fs.existsSync(hooksSrc)) {
@@ -1100,6 +1145,27 @@ async function install() {
1100
1145
  hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/session-end.sh' }]
1101
1146
  });
1102
1147
 
1148
+ // Stop hook: desktop notification (fires after session-end analytics)
1149
+ addHookIfMissing(settings.hooks.Stop, {
1150
+ hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/notify-desktop.sh' }]
1151
+ });
1152
+
1153
+ // Stop hook: webhook notification (Slack / Discord, fire-and-forget)
1154
+ addHookIfMissing(settings.hooks.Stop, {
1155
+ hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/notify-webhook.sh' }]
1156
+ });
1157
+
1158
+ // Stop hook: auto-memory sync (extracts session decisions → Sights cloud)
1159
+ addHookIfMissing(settings.hooks.Stop, {
1160
+ hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/session-end-memory-sync.sh' }]
1161
+ });
1162
+
1163
+ // Notification hook: desktop alert when Claude needs input
1164
+ settings.hooks.Notification = settings.hooks.Notification || [];
1165
+ addHookIfMissing(settings.hooks.Notification, {
1166
+ hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/notify-desktop.sh' }]
1167
+ });
1168
+
1103
1169
  // TeammateIdle hook (Agent Teams quality gate — only fires when Teams active)
1104
1170
  settings.hooks.TeammateIdle = settings.hooks.TeammateIdle || [];
1105
1171
  addHookIfMissing(settings.hooks.TeammateIdle, {
@@ -1124,6 +1190,48 @@ async function install() {
1124
1190
  hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/task-completed-verify.sh' }]
1125
1191
  });
1126
1192
 
1193
+ // InstructionsLoaded hook (cold-start Sights pre-warm)
1194
+ settings.hooks.InstructionsLoaded = settings.hooks.InstructionsLoaded || [];
1195
+ addHookIfMissing(settings.hooks.InstructionsLoaded, {
1196
+ hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/instructions-loaded.sh' }]
1197
+ });
1198
+
1199
+ // WorktreeCreate hook (propagate Merlin config into new worktrees)
1200
+ settings.hooks.WorktreeCreate = settings.hooks.WorktreeCreate || [];
1201
+ addHookIfMissing(settings.hooks.WorktreeCreate, {
1202
+ hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/worktree-create.sh' }]
1203
+ });
1204
+
1205
+ // WorktreeRemove hook (cleanup + lifecycle analytics)
1206
+ settings.hooks.WorktreeRemove = settings.hooks.WorktreeRemove || [];
1207
+ addHookIfMissing(settings.hooks.WorktreeRemove, {
1208
+ hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/worktree-remove.sh' }]
1209
+ });
1210
+
1211
+ // ConfigChange hook (validate API key + audit trail)
1212
+ settings.hooks.ConfigChange = settings.hooks.ConfigChange || [];
1213
+ addHookIfMissing(settings.hooks.ConfigChange, {
1214
+ hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/config-change.sh' }]
1215
+ });
1216
+
1217
+ // PostToolUse: file size enforcement (implementation agents only)
1218
+ addHookIfMissing(settings.hooks.PostToolUse, {
1219
+ matcher: 'Edit|Write',
1220
+ hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/check-file-size.sh' }]
1221
+ });
1222
+
1223
+ // PreToolUse: security scanner (prompt injection, secrets, data exfiltration)
1224
+ addHookIfMissing(settings.hooks.PreToolUse, {
1225
+ matcher: 'Write|Edit|Bash|NotebookEdit',
1226
+ hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/security-scanner.sh' }]
1227
+ });
1228
+
1229
+ // PreToolUse: smart bash auto-approval (read-only safe, dangerous blocked, unknown pass-through)
1230
+ addHookIfMissing(settings.hooks.PreToolUse, {
1231
+ matcher: 'Bash',
1232
+ hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/smart-approve.sh' }]
1233
+ });
1234
+
1127
1235
  // --- Prompt-based hooks cleanup & registration ---
1128
1236
  // Remove ALL prompt-type hooks from Merlin (identified by type: 'prompt').
1129
1237
  // This prevents duplicates across version upgrades and removes broken hooks.
@@ -1144,6 +1252,10 @@ async function install() {
1144
1252
  settings.hooks.Notification = removeAllPromptHooks(settings.hooks.Notification);
1145
1253
  settings.hooks.TaskCompleted = settings.hooks.TaskCompleted || [];
1146
1254
  settings.hooks.TaskCompleted = removeAllPromptHooks(settings.hooks.TaskCompleted);
1255
+ settings.hooks.InstructionsLoaded = removeAllPromptHooks(settings.hooks.InstructionsLoaded || []);
1256
+ settings.hooks.WorktreeCreate = removeAllPromptHooks(settings.hooks.WorktreeCreate || []);
1257
+ settings.hooks.WorktreeRemove = removeAllPromptHooks(settings.hooks.WorktreeRemove || []);
1258
+ settings.hooks.ConfigChange = removeAllPromptHooks(settings.hooks.ConfigChange || []);
1147
1259
 
1148
1260
  // NOTE: The PreToolUse prompt hook has been REMOVED. It caused an infinite
1149
1261
  // rejection loop because the evaluator model cannot see conversation history
@@ -1189,8 +1301,8 @@ async function install() {
1189
1301
  return cfg;
1190
1302
  }
1191
1303
 
1192
- // Step 10: Optional Merlin Sights configuration
1193
- logStep('10/11', 'Merlin Sights configuration...');
1304
+ // Step 12: Optional Merlin Sights configuration
1305
+ logStep('12/13', 'Merlin Sights configuration...');
1194
1306
 
1195
1307
  // Check if API key is already configured (skip prompt on updates)
1196
1308
  let existingApiKey = '';
@@ -1321,8 +1433,20 @@ async function install() {
1321
1433
  logWarn('Skipped Merlin Sights (you can configure it later)');
1322
1434
  }
1323
1435
 
1324
- // Step 11: Set up shell integration
1325
- logStep('11/11', 'Setting up shell integration...');
1436
+ // Step 13: Configure non-Claude-Code runtimes
1437
+ logStep('13/13', 'Configuring additional runtimes...');
1438
+ configureRuntimes({
1439
+ runtimeFlag: RUNTIME_FLAG,
1440
+ useGlobalBinary,
1441
+ apiKey,
1442
+ logSuccess,
1443
+ logWarn,
1444
+ logInfo: (msg) => log(msg),
1445
+ quiet: true, // step 2 already printed the detection summary
1446
+ });
1447
+
1448
+ // Shell integration (runs after runtime adapters)
1449
+ log(`\n${colors.cyan}[shell]${colors.reset} Setting up shell integration...`);
1326
1450
  const shellConfigured = setupShellIntegration();
1327
1451
  if (shellConfigured) {
1328
1452
  log(`\n ${colors.yellow}IMPORTANT:${colors.reset} Run ${colors.cyan}source ~/.zshrc${colors.reset} or ${colors.bright}restart your terminal${colors.reset}`);