sinapse-ai 7.3.2 → 7.4.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 (241) hide show
  1. package/.codex/agents/ad-copywriter.md +4 -0
  2. package/.codex/agents/agent-forger.md +4 -0
  3. package/.codex/agents/analyst.md +92 -0
  4. package/.codex/agents/animation-interpreter.md +4 -0
  5. package/.codex/agents/animation-performance-engineer.md +4 -0
  6. package/.codex/agents/animations-orqx.md +57 -0
  7. package/.codex/agents/architect.md +87 -0
  8. package/.codex/agents/assessment-creator.md +4 -0
  9. package/.codex/agents/audience-intelligence.md +4 -0
  10. package/.codex/agents/blake-snyder.md +4 -0
  11. package/.codex/agents/brad-frost.md +46 -0
  12. package/.codex/agents/brand-archetype-strategist.md +4 -0
  13. package/.codex/agents/brand-auditor.md +4 -0
  14. package/.codex/agents/brand-collateral-designer.md +4 -0
  15. package/.codex/agents/brand-compiler.md +4 -0
  16. package/.codex/agents/brand-creative-engineer.md +4 -0
  17. package/.codex/agents/brand-culture-architect.md +4 -0
  18. package/.codex/agents/brand-growth-strategist.md +4 -0
  19. package/.codex/agents/brand-identity-designer.md +4 -0
  20. package/.codex/agents/brand-motion-vfx.md +4 -0
  21. package/.codex/agents/brand-naming-specialist.md +4 -0
  22. package/.codex/agents/brand-orqx.md +95 -0
  23. package/.codex/agents/brand-positioning-strategist.md +4 -0
  24. package/.codex/agents/brand-sonic-designer.md +4 -0
  25. package/.codex/agents/brand-strategist.md +4 -0
  26. package/.codex/agents/brand-system-architect.md +4 -0
  27. package/.codex/agents/brand-voice-writer.md +4 -0
  28. package/.codex/agents/brene-brown.md +4 -0
  29. package/.codex/agents/budget-controller.md +4 -0
  30. package/.codex/agents/campaign-analyst.md +4 -0
  31. package/.codex/agents/charlie-munger.md +4 -0
  32. package/.codex/agents/claude-orqx.md +72 -0
  33. package/.codex/agents/cloning-orqx.md +70 -0
  34. package/.codex/agents/cloud-security-engineer.md +4 -0
  35. package/.codex/agents/cognitive-extractor.md +4 -0
  36. package/.codex/agents/commercial-orqx.md +67 -0
  37. package/.codex/agents/competitive-intelligence.md +4 -0
  38. package/.codex/agents/compliance-officer.md +4 -0
  39. package/.codex/agents/config-engineer.md +4 -0
  40. package/.codex/agents/content-analyst.md +4 -0
  41. package/.codex/agents/content-capturer.md +4 -0
  42. package/.codex/agents/content-engineer.md +4 -0
  43. package/.codex/agents/content-governor.md +4 -0
  44. package/.codex/agents/content-orqx.md +77 -0
  45. package/.codex/agents/content-writer.md +4 -0
  46. package/.codex/agents/conversion-writer.md +4 -0
  47. package/.codex/agents/copy-chief.md +162 -0
  48. package/.codex/agents/copy-editor.md +4 -0
  49. package/.codex/agents/copy-orqx.md +65 -0
  50. package/.codex/agents/copy-strategist.md +4 -0
  51. package/.codex/agents/council-orqx.md +68 -0
  52. package/.codex/agents/courses-orqx.md +64 -0
  53. package/.codex/agents/creative-strategist.md +4 -0
  54. package/.codex/agents/cro-specialist.md +4 -0
  55. package/.codex/agents/cs-business-auditor.md +4 -0
  56. package/.codex/agents/cs-client-success.md +4 -0
  57. package/.codex/agents/cs-crm-specialist.md +4 -0
  58. package/.codex/agents/cs-funnel-architect.md +4 -0
  59. package/.codex/agents/cs-lead-generation-strategist.md +4 -0
  60. package/.codex/agents/cs-offer-designer.md +4 -0
  61. package/.codex/agents/cs-revops-analyst.md +4 -0
  62. package/.codex/agents/cs-sales-closer.md +4 -0
  63. package/.codex/agents/cs-sales-enablement.md +4 -0
  64. package/.codex/agents/css-motion-artist.md +4 -0
  65. package/.codex/agents/curriculum-designer.md +4 -0
  66. package/.codex/agents/cyber-chief.md +169 -0
  67. package/.codex/agents/cyber-orqx.md +67 -0
  68. package/.codex/agents/dan-harmon.md +4 -0
  69. package/.codex/agents/dan-mall.md +43 -0
  70. package/.codex/agents/data-chief.md +198 -0
  71. package/.codex/agents/data-engineer.md +109 -0
  72. package/.codex/agents/data-synthesizer.md +4 -0
  73. package/.codex/agents/dave-malouf.md +43 -0
  74. package/.codex/agents/db-sage.md +152 -0
  75. package/.codex/agents/deep-researcher.md +4 -0
  76. package/.codex/agents/derek-sivers.md +4 -0
  77. package/.codex/agents/design-chief.md +226 -0
  78. package/.codex/agents/design-orqx.md +65 -0
  79. package/.codex/agents/design-system.md +210 -0
  80. package/.codex/agents/dev.md +102 -0
  81. package/.codex/agents/devops.md +90 -0
  82. package/.codex/agents/direct-response-writer.md +4 -0
  83. package/.codex/agents/dx-accessibility-specialist.md +4 -0
  84. package/.codex/agents/dx-design-system-architect.md +4 -0
  85. package/.codex/agents/dx-frontend-engineer.md +4 -0
  86. package/.codex/agents/dx-interaction-designer.md +4 -0
  87. package/.codex/agents/dx-performance-engineer.md +4 -0
  88. package/.codex/agents/dx-ui-designer.md +4 -0
  89. package/.codex/agents/dx-ux-strategist.md +4 -0
  90. package/.codex/agents/editorial-strategist.md +4 -0
  91. package/.codex/agents/email-sequence-strategist.md +4 -0
  92. package/.codex/agents/finance-orqx.md +57 -0
  93. package/.codex/agents/funnel-copywriter.md +4 -0
  94. package/.codex/agents/ga-analytics-engineer.md +4 -0
  95. package/.codex/agents/ga-campaign-analyst.md +4 -0
  96. package/.codex/agents/ga-cro-specialist.md +4 -0
  97. package/.codex/agents/ga-data-analyst.md +4 -0
  98. package/.codex/agents/ga-growth-hacker.md +4 -0
  99. package/.codex/agents/ga-seo-strategist.md +4 -0
  100. package/.codex/agents/generative-particle-engineer.md +4 -0
  101. package/.codex/agents/google-ads-specialist.md +4 -0
  102. package/.codex/agents/growth-orqx.md +75 -0
  103. package/.codex/agents/headline-specialist.md +4 -0
  104. package/.codex/agents/hooks-architect.md +4 -0
  105. package/.codex/agents/incident-responder.md +4 -0
  106. package/.codex/agents/joseph-campbell.md +4 -0
  107. package/.codex/agents/kb-architect.md +4 -0
  108. package/.codex/agents/keith-johnstone.md +4 -0
  109. package/.codex/agents/kindra-hall.md +4 -0
  110. package/.codex/agents/launch-strategist.md +4 -0
  111. package/.codex/agents/legal-chief.md +199 -0
  112. package/.codex/agents/lesson-architect.md +4 -0
  113. package/.codex/agents/long-form-writer.md +4 -0
  114. package/.codex/agents/market-analyst.md +4 -0
  115. package/.codex/agents/marshall-ganz.md +4 -0
  116. package/.codex/agents/mcp-integrator.md +4 -0
  117. package/.codex/agents/meta-ads-specialist.md +4 -0
  118. package/.codex/agents/mind-synthesizer.md +4 -0
  119. package/.codex/agents/motion-choreographer.md +4 -0
  120. package/.codex/agents/nancy-duarte.md +4 -0
  121. package/.codex/agents/nano-banana-generator.md +42 -0
  122. package/.codex/agents/naval-ravikant.md +4 -0
  123. package/.codex/agents/network-security-engineer.md +4 -0
  124. package/.codex/agents/oren-klaff.md +4 -0
  125. package/.codex/agents/paidmedia-orqx.md +67 -0
  126. package/.codex/agents/park-howell.md +4 -0
  127. package/.codex/agents/patrick-lencioni.md +4 -0
  128. package/.codex/agents/penetration-tester.md +4 -0
  129. package/.codex/agents/performance-engineer.md +4 -0
  130. package/.codex/agents/persuasion-psychologist.md +4 -0
  131. package/.codex/agents/peter-thiel.md +4 -0
  132. package/.codex/agents/platform-specialist.md +4 -0
  133. package/.codex/agents/pm-creative-performance-analyst.md +4 -0
  134. package/.codex/agents/pm-youtube-ads-specialist.md +4 -0
  135. package/.codex/agents/pm.md +81 -0
  136. package/.codex/agents/po.md +85 -0
  137. package/.codex/agents/pricing-strategist.md +4 -0
  138. package/.codex/agents/product-orqx.md +57 -0
  139. package/.codex/agents/production-director.md +4 -0
  140. package/.codex/agents/profitability-analyst.md +4 -0
  141. package/.codex/agents/project-integrator.md +4 -0
  142. package/.codex/agents/proof-architect.md +4 -0
  143. package/.codex/agents/ps-client-product-manager.md +4 -0
  144. package/.codex/agents/ps-delivery-manager.md +4 -0
  145. package/.codex/agents/ps-discovery-lead.md +4 -0
  146. package/.codex/agents/ps-product-analyst.md +4 -0
  147. package/.codex/agents/ps-product-ops-specialist.md +4 -0
  148. package/.codex/agents/ps-product-strategist.md +4 -0
  149. package/.codex/agents/qa.md +98 -0
  150. package/.codex/agents/ray-dalio.md +4 -0
  151. package/.codex/agents/reid-hoffman.md +4 -0
  152. package/.codex/agents/research-orqx.md +67 -0
  153. package/.codex/agents/revenue-analyst.md +4 -0
  154. package/.codex/agents/roadmap-sentinel.md +4 -0
  155. package/.codex/agents/scroll-narrative-engineer.md +4 -0
  156. package/.codex/agents/shader-artist.md +4 -0
  157. package/.codex/agents/signal-intelligence.md +4 -0
  158. package/.codex/agents/simon-sinek.md +4 -0
  159. package/.codex/agents/sinapse-orqx.md +619 -0
  160. package/.codex/agents/skill-craftsman.md +4 -0
  161. package/.codex/agents/slide-designer.md +4 -0
  162. package/.codex/agents/sm.md +77 -0
  163. package/.codex/agents/soc-analyst.md +4 -0
  164. package/.codex/agents/sop-extractor.md +61 -0
  165. package/.codex/agents/source-hunter.md +4 -0
  166. package/.codex/agents/squad-assembler.md +4 -0
  167. package/.codex/agents/squad-chief.md +1553 -0
  168. package/.codex/agents/squad.md +66 -0
  169. package/.codex/agents/story-chief.md +180 -0
  170. package/.codex/agents/storytelling-orqx.md +65 -0
  171. package/.codex/agents/swarm-orqx.md +64 -0
  172. package/.codex/agents/threat-analyst.md +4 -0
  173. package/.codex/agents/threejs-architect.md +4 -0
  174. package/.codex/agents/tools-orqx.md +219 -0
  175. package/.codex/agents/traffic-masters-chief.md +211 -0
  176. package/.codex/agents/trend-forecaster.md +4 -0
  177. package/.codex/agents/ux-designer.md +124 -0
  178. package/.codex/agents/yvon-chouinard.md +4 -0
  179. package/.codex/instructions.md +82 -0
  180. package/.codex/skills/sinapse-analyst/SKILL.md +28 -0
  181. package/.codex/skills/sinapse-animations/SKILL.md +28 -0
  182. package/.codex/skills/sinapse-architect/SKILL.md +30 -0
  183. package/.codex/skills/sinapse-brand/SKILL.md +28 -0
  184. package/.codex/skills/sinapse-claude/SKILL.md +28 -0
  185. package/.codex/skills/sinapse-cloning/SKILL.md +28 -0
  186. package/.codex/skills/sinapse-commercial/SKILL.md +28 -0
  187. package/.codex/skills/sinapse-content/SKILL.md +28 -0
  188. package/.codex/skills/sinapse-copy/SKILL.md +28 -0
  189. package/.codex/skills/sinapse-council/SKILL.md +28 -0
  190. package/.codex/skills/sinapse-courses/SKILL.md +28 -0
  191. package/.codex/skills/sinapse-cyber/SKILL.md +28 -0
  192. package/.codex/skills/sinapse-data-engineer/SKILL.md +30 -0
  193. package/.codex/skills/sinapse-design/SKILL.md +28 -0
  194. package/.codex/skills/sinapse-dev/SKILL.md +30 -0
  195. package/.codex/skills/sinapse-devops/SKILL.md +30 -0
  196. package/.codex/skills/sinapse-finance/SKILL.md +28 -0
  197. package/.codex/skills/sinapse-growth/SKILL.md +28 -0
  198. package/.codex/skills/sinapse-orqx/SKILL.md +30 -0
  199. package/.codex/skills/sinapse-paidmedia/SKILL.md +28 -0
  200. package/.codex/skills/sinapse-pm/SKILL.md +30 -0
  201. package/.codex/skills/sinapse-po/SKILL.md +30 -0
  202. package/.codex/skills/sinapse-product/SKILL.md +28 -0
  203. package/.codex/skills/sinapse-qa/SKILL.md +30 -0
  204. package/.codex/skills/sinapse-research/SKILL.md +28 -0
  205. package/.codex/skills/sinapse-sm/SKILL.md +26 -0
  206. package/.codex/skills/sinapse-squad-creator/SKILL.md +30 -0
  207. package/.codex/skills/sinapse-storytelling/SKILL.md +28 -0
  208. package/.codex/skills/sinapse-swarm/SKILL.md +28 -0
  209. package/.codex/skills/sinapse-ux-design-expert/SKILL.md +23 -0
  210. package/.sinapse-ai/data/entity-registry.yaml +763 -765
  211. package/.sinapse-ai/development/templates/chrome-brain/knowledge-base/chrome-brain.md +161 -0
  212. package/.sinapse-ai/development/templates/chrome-brain/rules/chrome-brain-autoload.md +56 -0
  213. package/.sinapse-ai/development/templates/chrome-brain/scripts/chrome-brain-log.sh +67 -0
  214. package/.sinapse-ai/development/templates/chrome-brain/scripts/chrome-debug.sh +232 -0
  215. package/.sinapse-ai/development/templates/chrome-brain/scripts/chrome-ensure.sh +210 -0
  216. package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-animations.md +50 -0
  217. package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-brand.md +42 -0
  218. package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-claude.md +49 -0
  219. package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-cloning.md +50 -0
  220. package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-commercial.md +41 -0
  221. package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-content.md +45 -0
  222. package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-copy.md +44 -0
  223. package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-cybersecurity.md +42 -0
  224. package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-design.md +50 -0
  225. package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-growth.md +45 -0
  226. package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-paidmedia.md +47 -0
  227. package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-product.md +49 -0
  228. package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-research.md +41 -0
  229. package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-storytelling.md +41 -0
  230. package/.sinapse-ai/install-manifest.yaml +81 -5
  231. package/CHROME-BRAIN-INSTALL.md +93 -0
  232. package/README.md +28 -1
  233. package/bin/modules/chrome-brain-installer.js +757 -0
  234. package/bin/sinapse.js +18 -0
  235. package/install-chrome-brain.sh +1328 -0
  236. package/package.json +6 -1
  237. package/packages/installer/src/wizard/feedback.js +13 -13
  238. package/packages/installer/src/wizard/i18n.js +30 -0
  239. package/packages/sinapse-install/src/capabilities/chrome-brain.js +962 -0
  240. package/packages/sinapse-install/src/installer.js +60 -2
  241. package/sinapse/agents/sinapse-orqx.md +27 -0
@@ -0,0 +1,962 @@
1
+ /**
2
+ * Chrome Brain — Cross-platform Chrome Browser Automation Installer
3
+ *
4
+ * Installs the Chrome Brain capability for SINAPSE:
5
+ * - Detects Chrome binary across macOS, Linux, Windows, WSL
6
+ * - Creates launcher/logger scripts in user bin directory
7
+ * - Merges PreToolUse/PostToolUse hooks into ~/.claude/settings.json
8
+ * - Adds Chrome DevTools MCP to ~/.claude.json
9
+ * - Copies KB and rule templates to ~/.sinapse/ structure
10
+ * - Validates the full installation
11
+ *
12
+ * @module capabilities/chrome-brain
13
+ */
14
+
15
+ 'use strict';
16
+
17
+ const fs = require('fs');
18
+ const path = require('path');
19
+ const os = require('os');
20
+ const { execSync } = require('child_process');
21
+ const { detectOS, OS_TYPE } = require('../os-detector');
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // Constants
25
+ // ---------------------------------------------------------------------------
26
+
27
+ const DEBUG_PORT = 9222;
28
+ const DEBUG_PROFILE = path.join(os.homedir(), '.chrome-debug-profile');
29
+ const SINAPSE_DIR = path.join(os.homedir(), '.sinapse');
30
+ const CLAUDE_DIR = path.join(os.homedir(), '.claude');
31
+ const CLAUDE_JSON = path.join(os.homedir(), '.claude.json');
32
+ const CLAUDE_SETTINGS = path.join(CLAUDE_DIR, 'settings.json');
33
+
34
+ const SQUAD_NAMES = [
35
+ 'squad-animations',
36
+ 'squad-design',
37
+ 'squad-cloning',
38
+ 'squad-claude',
39
+ 'squad-paidmedia',
40
+ 'squad-growth',
41
+ 'squad-content',
42
+ 'squad-copy',
43
+ 'squad-research',
44
+ 'squad-cybersecurity',
45
+ 'squad-commercial',
46
+ 'squad-brand',
47
+ 'squad-storytelling',
48
+ 'squad-product',
49
+ ];
50
+
51
+ // ---------------------------------------------------------------------------
52
+ // Logging helpers
53
+ // ---------------------------------------------------------------------------
54
+
55
+ let _quiet = false;
56
+ const LOG = {
57
+ ok: (msg) => { if (!_quiet) console.log(` \x1b[32m[OK]\x1b[0m ${msg}`); },
58
+ fail: (msg) => console.log(` \x1b[31m[FAIL]\x1b[0m ${msg}`),
59
+ warn: (msg) => console.log(` \x1b[33m[WARN]\x1b[0m ${msg}`),
60
+ info: (msg) => { if (!_quiet) console.log(` \x1b[36m[INFO]\x1b[0m ${msg}`); },
61
+ step: (msg) => { if (!_quiet) console.log(`\n\x1b[1m${msg}\x1b[0m`); },
62
+ };
63
+
64
+ // ---------------------------------------------------------------------------
65
+ // Chrome Detection
66
+ // ---------------------------------------------------------------------------
67
+
68
+ /**
69
+ * Detects the Chrome (or Chromium) binary path for the current platform.
70
+ * @returns {{ found: boolean, path: string|null, variant: string|null }}
71
+ */
72
+ function detectChrome() {
73
+ const platform = process.platform;
74
+ const candidates = [];
75
+
76
+ if (platform === 'darwin') {
77
+ candidates.push({
78
+ path: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
79
+ variant: 'Google Chrome',
80
+ });
81
+ candidates.push({
82
+ path: '/Applications/Chromium.app/Contents/MacOS/Chromium',
83
+ variant: 'Chromium',
84
+ });
85
+ } else if (platform === 'win32') {
86
+ const pf = process.env.PROGRAMFILES || 'C:\\Program Files';
87
+ const pfx86 = process.env['PROGRAMFILES(X86)'] || 'C:\\Program Files (x86)';
88
+ const localAppData = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
89
+ candidates.push({
90
+ path: path.join(pf, 'Google', 'Chrome', 'Application', 'chrome.exe'),
91
+ variant: 'Google Chrome',
92
+ });
93
+ candidates.push({
94
+ path: path.join(pfx86, 'Google', 'Chrome', 'Application', 'chrome.exe'),
95
+ variant: 'Google Chrome (x86)',
96
+ });
97
+ candidates.push({
98
+ path: path.join(localAppData, 'Google', 'Chrome', 'Application', 'chrome.exe'),
99
+ variant: 'Google Chrome (User)',
100
+ });
101
+ // Try 'where' command as fallback
102
+ try {
103
+ const found = execSync('where chrome.exe 2>NUL', { encoding: 'utf8' }).trim().split(/\r?\n/)[0];
104
+ if (found) {
105
+ candidates.push({ path: found, variant: 'Google Chrome (PATH)' });
106
+ }
107
+ } catch {
108
+ // not in PATH
109
+ }
110
+ } else {
111
+ // Linux / WSL
112
+ candidates.push({ path: '/usr/bin/google-chrome', variant: 'Google Chrome' });
113
+ candidates.push({ path: '/usr/bin/google-chrome-stable', variant: 'Google Chrome Stable' });
114
+ candidates.push({ path: '/usr/bin/chromium-browser', variant: 'Chromium' });
115
+ candidates.push({ path: '/usr/bin/chromium', variant: 'Chromium' });
116
+ candidates.push({ path: '/snap/bin/chromium', variant: 'Chromium (Snap)' });
117
+ // Try 'which' as fallback
118
+ for (const bin of ['google-chrome', 'google-chrome-stable', 'chromium-browser', 'chromium']) {
119
+ try {
120
+ const found = execSync(`which ${bin} 2>/dev/null`, { encoding: 'utf8' }).trim();
121
+ if (found && !candidates.some((c) => c.path === found)) {
122
+ candidates.push({ path: found, variant: bin });
123
+ }
124
+ } catch {
125
+ // not found
126
+ }
127
+ }
128
+ }
129
+
130
+ for (const candidate of candidates) {
131
+ try {
132
+ if (fs.existsSync(candidate.path)) {
133
+ return { found: true, path: candidate.path, variant: candidate.variant };
134
+ }
135
+ } catch {
136
+ // permission error — skip
137
+ }
138
+ }
139
+
140
+ return { found: false, path: null, variant: null };
141
+ }
142
+
143
+ // ---------------------------------------------------------------------------
144
+ // Script Generators
145
+ // ---------------------------------------------------------------------------
146
+
147
+ /**
148
+ * Returns the bin directory for scripts based on OS.
149
+ * Unix: ~/.local/bin Windows: ~/.sinapse/bin
150
+ */
151
+ function getBinDir(osInfo) {
152
+ if (osInfo.type === OS_TYPE.WINDOWS) {
153
+ return path.join(os.homedir(), '.sinapse', 'bin');
154
+ }
155
+ return path.join(os.homedir(), '.local', 'bin');
156
+ }
157
+
158
+ /**
159
+ * Generates the chrome-ensure script content.
160
+ */
161
+ function generateChromeEnsure(chromePath, osInfo) {
162
+ if (osInfo.type === OS_TYPE.WINDOWS) {
163
+ // PowerShell script wrapped in a .cmd launcher
164
+ return `@echo off
165
+ powershell -NoProfile -ExecutionPolicy Bypass -Command ^
166
+ "$port = if ($args[0]) { $args[0] } else { ${DEBUG_PORT} };" ^
167
+ "$profile = '%USERPROFILE%\\.chrome-debug-profile';" ^
168
+ "$cdp = 'http://127.0.0.1:' + $port + '/json/version';" ^
169
+ "try { $r = Invoke-WebRequest -Uri $cdp -TimeoutSec 1 -UseBasicParsing -ErrorAction Stop; exit 0 } catch {};" ^
170
+ "$running = Get-NetTCPConnection -LocalPort $port -ErrorAction SilentlyContinue;" ^
171
+ "if (-not $running) {" ^
172
+ " Get-Process chrome -ErrorAction SilentlyContinue | Where-Object { $_.CommandLine -like '*chrome-debug-profile*' } | Stop-Process -Force -ErrorAction SilentlyContinue;" ^
173
+ " Start-Sleep -Seconds 1;" ^
174
+ "};" ^
175
+ "Start-Process '${chromePath.replace(/\\/g, '\\\\')}' -ArgumentList '--remote-debugging-port=' + $port, '--user-data-dir=' + $profile, '--no-first-run' -WindowStyle Hidden;" ^
176
+ "for ($i = 1; $i -le 20; $i++) {" ^
177
+ " Start-Sleep -Milliseconds 500;" ^
178
+ " try { $r = Invoke-WebRequest -Uri $cdp -TimeoutSec 1 -UseBasicParsing -ErrorAction Stop; exit 0 } catch {};" ^
179
+ "};" ^
180
+ "Write-Error 'BLOCKED: Chrome debug failed to start on port ' + $port + '. Run chrome-debug manually.';" ^
181
+ "exit 1"
182
+ `;
183
+ }
184
+
185
+ // Unix (macOS / Linux / WSL)
186
+ const portCheck = osInfo.type === OS_TYPE.MACOS
187
+ ? 'lsof -iTCP:$PORT -sTCP:LISTEN'
188
+ : 'ss -tlnp | grep -q ":$PORT " || lsof -iTCP:$PORT -sTCP:LISTEN 2>/dev/null';
189
+
190
+ return `#!/bin/bash
191
+ PORT="\${1:-${DEBUG_PORT}}"
192
+ PROFILE="${DEBUG_PROFILE}"
193
+ CDP="http://127.0.0.1:$PORT/json/version"
194
+ if curl -sf "$CDP" -o /dev/null --max-time 1; then
195
+ exit 0
196
+ fi
197
+ if ! ${portCheck} &>/dev/null; then
198
+ pgrep -f "user-data-dir=$PROFILE" | xargs kill 2>/dev/null
199
+ sleep 1
200
+ fi
201
+ "${chromePath}" \\
202
+ --remote-debugging-port="$PORT" \\
203
+ --user-data-dir="$PROFILE" \\
204
+ --no-first-run \\
205
+ &>/dev/null &
206
+ for i in {1..20}; do
207
+ if curl -sf "$CDP" -o /dev/null --max-time 1; then
208
+ exit 0
209
+ fi
210
+ sleep 0.5
211
+ done
212
+ echo "BLOCKED: Chrome debug failed to start on port $PORT. Run 'chrome-debug' manually." >&2
213
+ exit 1
214
+ `;
215
+ }
216
+
217
+ /**
218
+ * Generates the chrome-debug script content.
219
+ */
220
+ function generateChromeDebug(chromePath, osInfo) {
221
+ if (osInfo.type === OS_TYPE.WINDOWS) {
222
+ return `@echo off
223
+ powershell -NoProfile -ExecutionPolicy Bypass -Command ^
224
+ "$port = if ($args[0]) { $args[0] } else { ${DEBUG_PORT} };" ^
225
+ "$profile = '%USERPROFILE%\\.chrome-debug-profile';" ^
226
+ "try { $r = Invoke-WebRequest -Uri ('http://127.0.0.1:' + $port + '/json/version') -TimeoutSec 1 -UseBasicParsing -ErrorAction Stop; Write-Host 'Chrome debug already running on port' $port; exit 0 } catch {};" ^
227
+ "Write-Host 'Killing existing debug Chrome instances...';" ^
228
+ "Get-Process chrome -ErrorAction SilentlyContinue | Where-Object { $_.CommandLine -like '*chrome-debug-profile*' } | Stop-Process -Force -ErrorAction SilentlyContinue;" ^
229
+ "Start-Sleep -Seconds 2;" ^
230
+ "Write-Host 'Launching Chrome with remote debugging on port' $port '...';" ^
231
+ "Start-Process '${chromePath.replace(/\\/g, '\\\\')}' -ArgumentList '--remote-debugging-port=' + $port, '--user-data-dir=' + $profile, '--no-first-run' -WindowStyle Hidden;" ^
232
+ "for ($i = 1; $i -le 15; $i++) {" ^
233
+ " Start-Sleep -Seconds 1;" ^
234
+ " try { $r = Invoke-WebRequest -Uri ('http://127.0.0.1:' + $port + '/json/version') -TimeoutSec 1 -UseBasicParsing -ErrorAction Stop; Write-Host 'Chrome ready on port' $port; exit 0 } catch {};" ^
235
+ "};" ^
236
+ "Write-Error 'ERROR: Chrome failed to start with debugging';" ^
237
+ "exit 1"
238
+ `;
239
+ }
240
+
241
+ return `#!/bin/bash
242
+ PORT="\${1:-${DEBUG_PORT}}"
243
+ PROFILE="${DEBUG_PROFILE}"
244
+ if curl -s "http://127.0.0.1:$PORT/json/version" &>/dev/null; then
245
+ echo "Chrome debug already running on port $PORT"
246
+ exit 0
247
+ fi
248
+ echo "Killing existing debug Chrome instances..."
249
+ pgrep -f "user-data-dir=$PROFILE" | xargs kill 2>/dev/null
250
+ sleep 2
251
+ echo "Launching Chrome with remote debugging on port $PORT..."
252
+ "${chromePath}" \\
253
+ --remote-debugging-port="$PORT" \\
254
+ --user-data-dir="$PROFILE" \\
255
+ --no-first-run \\
256
+ &>/dev/null &
257
+ for i in {1..15}; do
258
+ if curl -s "http://127.0.0.1:$PORT/json/version" &>/dev/null; then
259
+ echo "Chrome ready on port $PORT"
260
+ exit 0
261
+ fi
262
+ sleep 1
263
+ done
264
+ echo "ERROR: Chrome failed to start with debugging"
265
+ exit 1
266
+ `;
267
+ }
268
+
269
+ /**
270
+ * Generates the chrome-brain-log script content.
271
+ */
272
+ function generateChromeBrainLog(osInfo) {
273
+ if (osInfo.type === OS_TYPE.WINDOWS) {
274
+ return `@echo off
275
+ powershell -NoProfile -ExecutionPolicy Bypass -Command ^
276
+ "$logDir = '%USERPROFILE%\\.chrome-brain';" ^
277
+ "$logFile = Join-Path $logDir ('session-' + (Get-Date -Format 'yyyyMMdd') + '.log');" ^
278
+ "$counterFile = Join-Path $logDir '.screenshot-count';" ^
279
+ "New-Item -ItemType Directory -Path $logDir -Force | Out-Null;" ^
280
+ "$toolName = if ($env:HOOK_TOOL_NAME) { $env:HOOK_TOOL_NAME } else { 'unknown' };" ^
281
+ "$ts = Get-Date -Format 'HH:mm:ss';" ^
282
+ "Add-Content -Path $logFile -Value ('$ts $toolName');" ^
283
+ "if ($toolName -match 'take_screenshot|take_snapshot') {" ^
284
+ " $count = 0;" ^
285
+ " if (Test-Path $counterFile) { $count = [int](Get-Content $counterFile) };" ^
286
+ " $count++;" ^
287
+ " Set-Content -Path $counterFile -Value $count;" ^
288
+ " if ($count -eq 12) { Write-Warning 'WARNING: 12 screenshots in this session. Consider saving state and rotating.' };" ^
289
+ " if ($count -ge 15) { Write-Error 'CRITICAL: 15+ screenshots. Session at risk of exceeding 20MB API limit. Save state NOW.' };" ^
290
+ "};" ^
291
+ "exit 0"
292
+ `;
293
+ }
294
+
295
+ return `#!/bin/bash
296
+ LOG_DIR="$HOME/.chrome-brain"
297
+ LOG_FILE="$LOG_DIR/session-$(date +%Y%m%d).log"
298
+ COUNTER_FILE="$LOG_DIR/.screenshot-count"
299
+ mkdir -p "$LOG_DIR"
300
+ TOOL_NAME="\${HOOK_TOOL_NAME:-unknown}"
301
+ TIMESTAMP=$(date +%H:%M:%S)
302
+ echo "$TIMESTAMP $TOOL_NAME" >> "$LOG_FILE"
303
+ if echo "$TOOL_NAME" | grep -qE "take_screenshot|take_snapshot"; then
304
+ COUNT=$(cat "$COUNTER_FILE" 2>/dev/null || echo 0)
305
+ COUNT=$((COUNT + 1))
306
+ echo "$COUNT" > "$COUNTER_FILE"
307
+ if [ "$COUNT" -eq 12 ]; then
308
+ echo "WARNING: 12 screenshots in this session. Consider saving state and rotating." >&2
309
+ elif [ "$COUNT" -ge 15 ]; then
310
+ echo "CRITICAL: 15+ screenshots. Session at risk of exceeding 20MB API limit. Save state NOW." >&2
311
+ fi
312
+ fi
313
+ exit 0
314
+ `;
315
+ }
316
+
317
+ // ---------------------------------------------------------------------------
318
+ // JSON Merge Helpers
319
+ // ---------------------------------------------------------------------------
320
+
321
+ /**
322
+ * Safely reads a JSON file. Returns empty object on failure.
323
+ */
324
+ function readJsonSafe(filePath) {
325
+ try {
326
+ if (fs.existsSync(filePath)) {
327
+ const raw = fs.readFileSync(filePath, 'utf8');
328
+ return JSON.parse(raw);
329
+ }
330
+ } catch (err) {
331
+ LOG.warn(`Could not parse ${filePath}: ${err.message}`);
332
+ }
333
+ return {};
334
+ }
335
+
336
+ /**
337
+ * Writes a JSON file with pretty-printing.
338
+ */
339
+ function writeJson(filePath, data) {
340
+ const dir = path.dirname(filePath);
341
+ fs.mkdirSync(dir, { recursive: true });
342
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
343
+ }
344
+
345
+ /**
346
+ * Merges Chrome Brain hooks into ~/.claude/settings.json.
347
+ * Preserves all existing hooks — only replaces entries with matching matchers.
348
+ */
349
+ function mergeHooks() {
350
+ const newHooks = {
351
+ PreToolUse: [
352
+ { matcher: 'mcp__chrome-devtools__*', hooks: [{ type: 'command', command: 'chrome-ensure' }] },
353
+ { matcher: 'mcp__claude-in-chrome__*', hooks: [{ type: 'command', command: 'chrome-ensure' }] },
354
+ ],
355
+ PostToolUse: [
356
+ { matcher: 'mcp__chrome-devtools__*', hooks: [{ type: 'command', command: 'chrome-brain-log' }] },
357
+ { matcher: 'mcp__claude-in-chrome__*', hooks: [{ type: 'command', command: 'chrome-brain-log' }] },
358
+ ],
359
+ };
360
+
361
+ const settings = readJsonSafe(CLAUDE_SETTINGS);
362
+ if (!settings.hooks) {
363
+ settings.hooks = {};
364
+ }
365
+
366
+ for (const [hookType, hookList] of Object.entries(newHooks)) {
367
+ const existing = settings.hooks[hookType] || [];
368
+ const newMatchers = new Set(hookList.map((h) => h.matcher));
369
+ const filtered = existing.filter((e) => !newMatchers.has(e.matcher));
370
+ filtered.push(...hookList);
371
+ settings.hooks[hookType] = filtered;
372
+ }
373
+
374
+ writeJson(CLAUDE_SETTINGS, settings);
375
+ }
376
+
377
+ /**
378
+ * Adds Chrome DevTools MCP server to ~/.claude.json.
379
+ */
380
+ function mergeMcpConfig(osInfo) {
381
+ const config = readJsonSafe(CLAUDE_JSON);
382
+ if (!config.mcpServers) {
383
+ config.mcpServers = {};
384
+ }
385
+
386
+ if (osInfo.type === OS_TYPE.WINDOWS) {
387
+ config.mcpServers['chrome-devtools'] = {
388
+ command: 'cmd',
389
+ args: ['/c', 'npx', '-y', 'chrome-devtools-mcp@latest', '--browser-url=http://127.0.0.1:9222'],
390
+ };
391
+ } else {
392
+ config.mcpServers['chrome-devtools'] = {
393
+ command: 'npx',
394
+ args: ['chrome-devtools-mcp@latest', '--browser-url=http://127.0.0.1:9222'],
395
+ };
396
+ }
397
+
398
+ writeJson(CLAUDE_JSON, config);
399
+ }
400
+
401
+ // ---------------------------------------------------------------------------
402
+ // Template / KB Content
403
+ // ---------------------------------------------------------------------------
404
+
405
+ function getAutoloadRuleContent() {
406
+ return `# Chrome Brain — Auto-Activation & Auto-Learning Rule
407
+
408
+ > CRITICAL: This capability auto-activates and auto-learns. No command needed.
409
+
410
+ ## Auto-Activation
411
+
412
+ When the user's prompt matches ANY of these patterns, Chrome Brain is active:
413
+
414
+ - **Browser**: abrir/navegar/acessar site, URL, pagina, chrome, aba
415
+ - **Cloning**: clonar/replicar/copiar site, pagina, hero, layout, animacao
416
+ - **Forms**: preencher/cadastrar/signup/login formulario, form, conta
417
+ - **Audit**: auditar/analisar/inspecionar site, performance, Lighthouse
418
+ - **Scraping**: extrair/scrape/coletar dados, conteudo, HTML, CSS
419
+ - **Animation**: animacao 3D, Three.js, WebGL, shader, canvas
420
+
421
+ ## Protocol
422
+
423
+ 1. Chrome connection is guaranteed by PreToolUse hook (chrome-ensure)
424
+ 2. Select tooling: CDP > dev-browser > claude-in-chrome
425
+ 3. Execute with NSN Mode enabled (never say "I can't" — try 3+ alternatives)
426
+ 4. Track screenshot count — max 15 per session
427
+ 5. Handoff results to domain squad when applicable
428
+
429
+ ## Auto-Learning — MANDATORY
430
+
431
+ After completing ANY browser automation task, evaluate:
432
+
433
+ 1. **Did something unexpected happen?** (error, workaround, new pattern)
434
+ 2. **Did NSN Mode activate?** (barrier encountered and resolved)
435
+ 3. **Is the solution generalizable?** (useful for future sessions)
436
+
437
+ If YES to any:
438
+ - Append the learning to the Learnings Log section in:
439
+ ~/.sinapse/sinapse/knowledge-base/chrome-brain.md
440
+
441
+ ## Session Management
442
+
443
+ Track screenshots mentally. When approaching 12:
444
+ 1. Save current state to handoff file
445
+ 2. Suggest session rotation to user
446
+ 3. Never exceed 15 screenshots in a single session
447
+
448
+ ## Knowledge Base
449
+
450
+ Full reference: ~/.sinapse/sinapse/knowledge-base/chrome-brain.md
451
+ `;
452
+ }
453
+
454
+ function getMasterKbContent() {
455
+ return `# Chrome Brain — Browser Automation Capability
456
+
457
+ > Cross-squad capability que da a TODOS os agents do SINAPSE o poder de
458
+ > navegar, clonar, preencher, auditar e scrape qualquer site via Chrome real.
459
+ > Auto-ativado. Sem comando manual. NSN Mode sempre ligado.
460
+
461
+ ---
462
+
463
+ ## Arquitetura
464
+
465
+ \`\`\`
466
+ Chrome (porta 9222, perfil ~/.chrome-debug-profile)
467
+ +-- Chrome DevTools MCP (29 tools) — acoes rapidas, screenshots, Lighthouse
468
+ +-- dev-browser (Playwright) — scraping complexo, batch, headless
469
+ +-- claude-in-chrome (Extension) — fallback visual, coordenadas de tela
470
+ \`\`\`
471
+
472
+ **Prioridade de tooling:** CDP > dev-browser > claude-in-chrome
473
+
474
+ **Auto-launch:** Hook PreToolUse roda chrome-ensure antes de qualquer tool chrome.
475
+
476
+ ---
477
+
478
+ ## Decisao de Tooling
479
+
480
+ | Cenario | Ferramenta |
481
+ |---------|-----------|
482
+ | Click, fill, navegar | Chrome DevTools MCP |
483
+ | Screenshot/snapshot | Chrome DevTools MCP |
484
+ | Performance/Lighthouse | Chrome DevTools MCP |
485
+ | Network/Console | Chrome DevTools MCP |
486
+ | Scraping com logica JS | dev-browser evaluate() |
487
+ | Batch/loops | dev-browser |
488
+ | Headless | dev-browser --headless |
489
+ | Iframe cross-origin | claude-in-chrome ou CDP Input.dispatchMouseEvent |
490
+
491
+ ---
492
+
493
+ ## NSN Mode — Nunca Diga Nunca
494
+
495
+ Quando encontrar barreira:
496
+ 1. Classificar — permission? technical? knowledge? external?
497
+ 2. Buscar workaround via web search
498
+ 3. Tentar alternativas — minimo 3 abordagens diferentes
499
+ 4. Configurar e testar
500
+ 5. Repetir (max 5 ciclos)
501
+ 6. Escalar ao usuario com detalhes
502
+
503
+ ---
504
+
505
+ ## Session Management
506
+
507
+ - Max 15 screenshots por sessao
508
+ - Max 10 snapshots por sessao
509
+ - Preferir evaluate_script sobre take_snapshot
510
+ - Rotacionar sessao a cada ~12 screenshots
511
+
512
+ ---
513
+
514
+ ## Learnings Log
515
+
516
+ > Secao atualizada automaticamente quando NSN Mode resolve problemas novos.
517
+
518
+ `;
519
+ }
520
+
521
+ function getSquadIntegrationContent(squadName) {
522
+ const footer = `## Tools Disponiveis
523
+
524
+ 1. **Chrome DevTools MCP** (29 tools) — acoes rapidas, screenshots, audit
525
+ 2. **dev-browser** — scraping complexo, batch operations
526
+ 3. **claude-in-chrome** — fallback visual
527
+
528
+ ## Session Management
529
+
530
+ - Max 15 screenshots por sessao
531
+ - Salvar outputs em arquivo antes de acumular
532
+ - Rotacionar sessao a cada ~12 screenshots
533
+
534
+ ## NSN Mode
535
+
536
+ Ativo. Se uma acao de browser falhar, tentar alternativas automaticamente.
537
+
538
+ ## Referencia Completa
539
+
540
+ ~/.sinapse/sinapse/knowledge-base/chrome-brain.md
541
+ `;
542
+
543
+ return `# Chrome Brain Integration — ${squadName}
544
+
545
+ > This squad has access to Chrome Brain for browser automation tasks.
546
+ > Auto-activated when browser interaction is needed.
547
+
548
+ ## Tier: 2
549
+
550
+ ## When to Activate
551
+
552
+ - User task requires browser interaction relevant to this squad's domain
553
+ - Data extraction from web sources
554
+ - Visual validation of deliverables in browser
555
+ - Automated form filling or navigation
556
+
557
+ ## What This Squad Receives from Chrome Brain
558
+
559
+ - DOM snapshots and screenshots
560
+ - Extracted data (text, styles, assets)
561
+ - Performance and accessibility audits
562
+ - Network and console monitoring data
563
+
564
+ ## What This Squad Sends to Chrome Brain
565
+
566
+ - URLs and targets for capture
567
+ - Custom extraction scripts
568
+ - Deliverables for visual validation
569
+
570
+ ${footer}`;
571
+ }
572
+
573
+ // ---------------------------------------------------------------------------
574
+ // Core Install / Uninstall
575
+ // ---------------------------------------------------------------------------
576
+
577
+ /**
578
+ * Full Chrome Brain installation.
579
+ *
580
+ * @param {Object} [options={}]
581
+ * @param {boolean} [options.dryRun=false] Log actions without writing files
582
+ * @param {boolean} [options.skipMcp=false] Skip MCP config merge
583
+ * @param {boolean} [options.skipHooks=false] Skip hook merge
584
+ * @param {boolean} [options.skipKb=false] Skip knowledge base copy
585
+ * @param {boolean} [options.skipScripts=false] Skip script creation
586
+ * @returns {{ success: boolean, chrome: object, errors: string[] }}
587
+ */
588
+ function installChromeBrain(options = {}) {
589
+ const { dryRun = false, skipMcp = false, skipHooks = false, skipKb = false, skipScripts = false, quiet = false } = options;
590
+ _quiet = quiet;
591
+ const errors = [];
592
+ const osInfo = detectOS();
593
+
594
+ LOG.step('Chrome Brain Installer');
595
+ LOG.info(`OS: ${osInfo.type} | Platform: ${osInfo.platform} | Arch: ${osInfo.arch}`);
596
+
597
+ // --- Step 1: Detect Chrome ---
598
+ LOG.step('Step 1 — Detecting Chrome...');
599
+ const chrome = detectChrome();
600
+ if (!chrome.found) {
601
+ LOG.fail('Google Chrome not found. Install Chrome and retry.');
602
+ return { success: false, chrome, errors: ['Chrome not found'] };
603
+ }
604
+ LOG.ok(`${chrome.variant} at ${chrome.path}`);
605
+
606
+ // --- Step 2: Create scripts ---
607
+ if (!skipScripts) {
608
+ LOG.step('Step 2 — Creating launcher scripts...');
609
+ const binDir = getBinDir(osInfo);
610
+ const ext = osInfo.type === OS_TYPE.WINDOWS ? '.cmd' : '';
611
+ const scripts = {
612
+ [`chrome-ensure${ext}`]: generateChromeEnsure(chrome.path, osInfo),
613
+ [`chrome-debug${ext}`]: generateChromeDebug(chrome.path, osInfo),
614
+ [`chrome-brain-log${ext}`]: generateChromeBrainLog(osInfo),
615
+ };
616
+
617
+ try {
618
+ if (!dryRun) {
619
+ fs.mkdirSync(binDir, { recursive: true });
620
+ }
621
+ for (const [name, content] of Object.entries(scripts)) {
622
+ const filePath = path.join(binDir, name);
623
+ if (dryRun) {
624
+ LOG.info(`[DRY-RUN] Would create ${filePath}`);
625
+ } else {
626
+ fs.writeFileSync(filePath, content, 'utf8');
627
+ // Make executable on Unix
628
+ if (osInfo.type !== OS_TYPE.WINDOWS) {
629
+ fs.chmodSync(filePath, 0o755);
630
+ }
631
+ LOG.ok(`${name} created`);
632
+ }
633
+ }
634
+
635
+ // Warn if binDir not in PATH
636
+ const pathDirs = (process.env.PATH || '').split(path.delimiter);
637
+ if (!pathDirs.some((d) => d === binDir || d === binDir + path.sep)) {
638
+ LOG.warn(`${binDir} may not be in your PATH. Add it to your shell profile.`);
639
+ }
640
+ } catch (err) {
641
+ const msg = `Failed to create scripts: ${err.message}`;
642
+ LOG.fail(msg);
643
+ errors.push(msg);
644
+ }
645
+ }
646
+
647
+ // --- Step 3: Merge hooks ---
648
+ if (!skipHooks) {
649
+ LOG.step('Step 3 — Merging hooks into ~/.claude/settings.json...');
650
+ try {
651
+ if (dryRun) {
652
+ LOG.info('[DRY-RUN] Would merge hooks into settings.json');
653
+ } else {
654
+ fs.mkdirSync(CLAUDE_DIR, { recursive: true });
655
+ mergeHooks();
656
+ LOG.ok('Hooks merged into ~/.claude/settings.json');
657
+ }
658
+ } catch (err) {
659
+ const msg = `Failed to merge hooks: ${err.message}`;
660
+ LOG.fail(msg);
661
+ errors.push(msg);
662
+ }
663
+ }
664
+
665
+ // --- Step 4: MCP config ---
666
+ if (!skipMcp) {
667
+ LOG.step('Step 4 — Adding Chrome DevTools MCP to ~/.claude.json...');
668
+ try {
669
+ if (dryRun) {
670
+ LOG.info('[DRY-RUN] Would merge MCP config');
671
+ } else {
672
+ mergeMcpConfig(osInfo);
673
+ LOG.ok('Chrome DevTools MCP added to ~/.claude.json');
674
+ }
675
+ } catch (err) {
676
+ const msg = `Failed to merge MCP config: ${err.message}`;
677
+ LOG.fail(msg);
678
+ errors.push(msg);
679
+ }
680
+ }
681
+
682
+ // --- Step 5: KB and rules ---
683
+ if (!skipKb) {
684
+ LOG.step('Step 5 — Installing knowledge base and rules...');
685
+ const kbFiles = [
686
+ {
687
+ path: path.join(SINAPSE_DIR, '.claude', 'rules', 'chrome-brain-autoload.md'),
688
+ content: getAutoloadRuleContent(),
689
+ label: 'chrome-brain-autoload.md rule',
690
+ },
691
+ {
692
+ path: path.join(SINAPSE_DIR, 'sinapse', 'knowledge-base', 'chrome-brain.md'),
693
+ content: getMasterKbContent(),
694
+ label: 'master KB chrome-brain.md',
695
+ },
696
+ ];
697
+
698
+ // Squad integration files
699
+ for (const squad of SQUAD_NAMES) {
700
+ kbFiles.push({
701
+ path: path.join(SINAPSE_DIR, squad, 'knowledge-base', 'chrome-brain-integration.md'),
702
+ content: getSquadIntegrationContent(squad),
703
+ label: `${squad}/chrome-brain-integration.md`,
704
+ });
705
+ }
706
+
707
+ for (const file of kbFiles) {
708
+ try {
709
+ if (dryRun) {
710
+ LOG.info(`[DRY-RUN] Would create ${file.label}`);
711
+ } else {
712
+ fs.mkdirSync(path.dirname(file.path), { recursive: true });
713
+ fs.writeFileSync(file.path, file.content, 'utf8');
714
+ LOG.ok(file.label);
715
+ }
716
+ } catch (err) {
717
+ const msg = `Failed to create ${file.label}: ${err.message}`;
718
+ LOG.fail(msg);
719
+ errors.push(msg);
720
+ }
721
+ }
722
+ }
723
+
724
+ // --- Step 6: Validate ---
725
+ LOG.step('Step 6 — Validating installation...');
726
+ if (!dryRun) {
727
+ const status = getChromeBrainStatus();
728
+ const total = Object.values(status.components).filter((v) => v === true).length;
729
+ const count = Object.keys(status.components).length;
730
+ if (total === count) {
731
+ LOG.ok(`All ${count} components validated successfully`);
732
+ } else {
733
+ LOG.warn(`${total}/${count} components validated — check warnings above`);
734
+ }
735
+ }
736
+
737
+ const success = errors.length === 0;
738
+ if (success) {
739
+ LOG.step('Chrome Brain installed successfully!');
740
+ } else {
741
+ LOG.step(`Chrome Brain installed with ${errors.length} error(s)`);
742
+ }
743
+
744
+ return { success, chrome, errors };
745
+ }
746
+
747
+ /**
748
+ * Removes the Chrome Brain capability.
749
+ *
750
+ * @param {Object} [options={}]
751
+ * @param {boolean} [options.dryRun=false] Log actions without deleting files
752
+ * @param {boolean} [options.keepKb=false] Preserve knowledge base files
753
+ * @returns {{ success: boolean, removed: string[], errors: string[] }}
754
+ */
755
+ function uninstallChromeBrain(options = {}) {
756
+ const { dryRun = false, keepKb = false } = options;
757
+ const osInfo = detectOS();
758
+ const removed = [];
759
+ const errors = [];
760
+
761
+ LOG.step('Chrome Brain Uninstaller');
762
+
763
+ // --- Remove scripts ---
764
+ const binDir = getBinDir(osInfo);
765
+ const ext = osInfo.type === OS_TYPE.WINDOWS ? '.cmd' : '';
766
+ const scriptNames = [`chrome-ensure${ext}`, `chrome-debug${ext}`, `chrome-brain-log${ext}`];
767
+
768
+ for (const name of scriptNames) {
769
+ const filePath = path.join(binDir, name);
770
+ try {
771
+ if (fs.existsSync(filePath)) {
772
+ if (dryRun) {
773
+ LOG.info(`[DRY-RUN] Would remove ${filePath}`);
774
+ } else {
775
+ fs.unlinkSync(filePath);
776
+ LOG.ok(`Removed ${name}`);
777
+ }
778
+ removed.push(filePath);
779
+ }
780
+ } catch (err) {
781
+ errors.push(`Failed to remove ${name}: ${err.message}`);
782
+ }
783
+ }
784
+
785
+ // --- Remove hooks from settings.json ---
786
+ try {
787
+ const settings = readJsonSafe(CLAUDE_SETTINGS);
788
+ if (settings.hooks) {
789
+ const chromeMatchers = new Set([
790
+ 'mcp__chrome-devtools__*',
791
+ 'mcp__claude-in-chrome__*',
792
+ ]);
793
+ let changed = false;
794
+ for (const hookType of ['PreToolUse', 'PostToolUse']) {
795
+ if (Array.isArray(settings.hooks[hookType])) {
796
+ const before = settings.hooks[hookType].length;
797
+ settings.hooks[hookType] = settings.hooks[hookType].filter(
798
+ (e) => !chromeMatchers.has(e.matcher),
799
+ );
800
+ if (settings.hooks[hookType].length < before) {
801
+ changed = true;
802
+ }
803
+ }
804
+ }
805
+ if (changed) {
806
+ if (dryRun) {
807
+ LOG.info('[DRY-RUN] Would remove Chrome hooks from settings.json');
808
+ } else {
809
+ writeJson(CLAUDE_SETTINGS, settings);
810
+ LOG.ok('Removed Chrome hooks from settings.json');
811
+ }
812
+ removed.push(CLAUDE_SETTINGS);
813
+ }
814
+ }
815
+ } catch (err) {
816
+ errors.push(`Failed to clean hooks: ${err.message}`);
817
+ }
818
+
819
+ // --- Remove MCP from claude.json ---
820
+ try {
821
+ const config = readJsonSafe(CLAUDE_JSON);
822
+ if (config.mcpServers && config.mcpServers['chrome-devtools']) {
823
+ if (dryRun) {
824
+ LOG.info('[DRY-RUN] Would remove chrome-devtools from ~/.claude.json');
825
+ } else {
826
+ delete config.mcpServers['chrome-devtools'];
827
+ writeJson(CLAUDE_JSON, config);
828
+ LOG.ok('Removed chrome-devtools MCP from ~/.claude.json');
829
+ }
830
+ removed.push(CLAUDE_JSON);
831
+ }
832
+ } catch (err) {
833
+ errors.push(`Failed to clean MCP config: ${err.message}`);
834
+ }
835
+
836
+ // --- Remove KB files ---
837
+ if (!keepKb) {
838
+ const kbPaths = [
839
+ path.join(SINAPSE_DIR, '.claude', 'rules', 'chrome-brain-autoload.md'),
840
+ path.join(SINAPSE_DIR, 'sinapse', 'knowledge-base', 'chrome-brain.md'),
841
+ ];
842
+ for (const squad of SQUAD_NAMES) {
843
+ kbPaths.push(path.join(SINAPSE_DIR, squad, 'knowledge-base', 'chrome-brain-integration.md'));
844
+ }
845
+ for (const kbPath of kbPaths) {
846
+ try {
847
+ if (fs.existsSync(kbPath)) {
848
+ if (dryRun) {
849
+ LOG.info(`[DRY-RUN] Would remove ${path.basename(kbPath)}`);
850
+ } else {
851
+ fs.unlinkSync(kbPath);
852
+ LOG.ok(`Removed ${path.basename(kbPath)}`);
853
+ }
854
+ removed.push(kbPath);
855
+ }
856
+ } catch (err) {
857
+ errors.push(`Failed to remove ${kbPath}: ${err.message}`);
858
+ }
859
+ }
860
+ }
861
+
862
+ const success = errors.length === 0;
863
+ LOG.step(success ? 'Chrome Brain uninstalled.' : `Uninstall completed with ${errors.length} error(s)`);
864
+ return { success, removed, errors };
865
+ }
866
+
867
+ // ---------------------------------------------------------------------------
868
+ // Status
869
+ // ---------------------------------------------------------------------------
870
+
871
+ /**
872
+ * Checks installation status of all Chrome Brain components.
873
+ *
874
+ * @returns {{
875
+ * installed: boolean,
876
+ * chrome: { found: boolean, path: string|null, variant: string|null },
877
+ * components: {
878
+ * chromeDetected: boolean,
879
+ * scriptsInstalled: boolean,
880
+ * hooksConfigured: boolean,
881
+ * mcpConfigured: boolean,
882
+ * ruleInstalled: boolean,
883
+ * masterKbInstalled: boolean,
884
+ * squadKbCount: number
885
+ * }
886
+ * }}
887
+ */
888
+ function getChromeBrainStatus() {
889
+ const osInfo = detectOS();
890
+ const chrome = detectChrome();
891
+ const binDir = getBinDir(osInfo);
892
+ const ext = osInfo.type === OS_TYPE.WINDOWS ? '.cmd' : '';
893
+
894
+ // Check scripts
895
+ const scriptsInstalled = ['chrome-ensure', 'chrome-debug', 'chrome-brain-log']
896
+ .every((name) => fs.existsSync(path.join(binDir, `${name}${ext}`)));
897
+
898
+ // Check hooks
899
+ let hooksConfigured = false;
900
+ try {
901
+ const settings = readJsonSafe(CLAUDE_SETTINGS);
902
+ const pre = settings.hooks?.PreToolUse || [];
903
+ const post = settings.hooks?.PostToolUse || [];
904
+ const hasPre = pre.some((h) => h.matcher === 'mcp__chrome-devtools__*');
905
+ const hasPost = post.some((h) => h.matcher === 'mcp__chrome-devtools__*');
906
+ hooksConfigured = hasPre && hasPost;
907
+ } catch {
908
+ // not configured
909
+ }
910
+
911
+ // Check MCP
912
+ let mcpConfigured = false;
913
+ try {
914
+ const config = readJsonSafe(CLAUDE_JSON);
915
+ mcpConfigured = !!config.mcpServers?.['chrome-devtools'];
916
+ } catch {
917
+ // not configured
918
+ }
919
+
920
+ // Check rule
921
+ const ruleInstalled = fs.existsSync(
922
+ path.join(SINAPSE_DIR, '.claude', 'rules', 'chrome-brain-autoload.md'),
923
+ );
924
+
925
+ // Check master KB
926
+ const masterKbInstalled = fs.existsSync(
927
+ path.join(SINAPSE_DIR, 'sinapse', 'knowledge-base', 'chrome-brain.md'),
928
+ );
929
+
930
+ // Count squad KBs
931
+ let squadKbCount = 0;
932
+ for (const squad of SQUAD_NAMES) {
933
+ if (fs.existsSync(path.join(SINAPSE_DIR, squad, 'knowledge-base', 'chrome-brain-integration.md'))) {
934
+ squadKbCount++;
935
+ }
936
+ }
937
+
938
+ const components = {
939
+ chromeDetected: chrome.found,
940
+ scriptsInstalled,
941
+ hooksConfigured,
942
+ mcpConfigured,
943
+ ruleInstalled,
944
+ masterKbInstalled,
945
+ squadKbComplete: squadKbCount === SQUAD_NAMES.length,
946
+ };
947
+
948
+ const installed = Object.values(components).every((v) => v === true);
949
+
950
+ return { installed, chrome, components, squadKbCount };
951
+ }
952
+
953
+ // ---------------------------------------------------------------------------
954
+ // Exports
955
+ // ---------------------------------------------------------------------------
956
+
957
+ module.exports = {
958
+ installChromeBrain,
959
+ uninstallChromeBrain,
960
+ getChromeBrainStatus,
961
+ detectChrome,
962
+ };