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.
- package/.codex/agents/ad-copywriter.md +4 -0
- package/.codex/agents/agent-forger.md +4 -0
- package/.codex/agents/analyst.md +92 -0
- package/.codex/agents/animation-interpreter.md +4 -0
- package/.codex/agents/animation-performance-engineer.md +4 -0
- package/.codex/agents/animations-orqx.md +57 -0
- package/.codex/agents/architect.md +87 -0
- package/.codex/agents/assessment-creator.md +4 -0
- package/.codex/agents/audience-intelligence.md +4 -0
- package/.codex/agents/blake-snyder.md +4 -0
- package/.codex/agents/brad-frost.md +46 -0
- package/.codex/agents/brand-archetype-strategist.md +4 -0
- package/.codex/agents/brand-auditor.md +4 -0
- package/.codex/agents/brand-collateral-designer.md +4 -0
- package/.codex/agents/brand-compiler.md +4 -0
- package/.codex/agents/brand-creative-engineer.md +4 -0
- package/.codex/agents/brand-culture-architect.md +4 -0
- package/.codex/agents/brand-growth-strategist.md +4 -0
- package/.codex/agents/brand-identity-designer.md +4 -0
- package/.codex/agents/brand-motion-vfx.md +4 -0
- package/.codex/agents/brand-naming-specialist.md +4 -0
- package/.codex/agents/brand-orqx.md +95 -0
- package/.codex/agents/brand-positioning-strategist.md +4 -0
- package/.codex/agents/brand-sonic-designer.md +4 -0
- package/.codex/agents/brand-strategist.md +4 -0
- package/.codex/agents/brand-system-architect.md +4 -0
- package/.codex/agents/brand-voice-writer.md +4 -0
- package/.codex/agents/brene-brown.md +4 -0
- package/.codex/agents/budget-controller.md +4 -0
- package/.codex/agents/campaign-analyst.md +4 -0
- package/.codex/agents/charlie-munger.md +4 -0
- package/.codex/agents/claude-orqx.md +72 -0
- package/.codex/agents/cloning-orqx.md +70 -0
- package/.codex/agents/cloud-security-engineer.md +4 -0
- package/.codex/agents/cognitive-extractor.md +4 -0
- package/.codex/agents/commercial-orqx.md +67 -0
- package/.codex/agents/competitive-intelligence.md +4 -0
- package/.codex/agents/compliance-officer.md +4 -0
- package/.codex/agents/config-engineer.md +4 -0
- package/.codex/agents/content-analyst.md +4 -0
- package/.codex/agents/content-capturer.md +4 -0
- package/.codex/agents/content-engineer.md +4 -0
- package/.codex/agents/content-governor.md +4 -0
- package/.codex/agents/content-orqx.md +77 -0
- package/.codex/agents/content-writer.md +4 -0
- package/.codex/agents/conversion-writer.md +4 -0
- package/.codex/agents/copy-chief.md +162 -0
- package/.codex/agents/copy-editor.md +4 -0
- package/.codex/agents/copy-orqx.md +65 -0
- package/.codex/agents/copy-strategist.md +4 -0
- package/.codex/agents/council-orqx.md +68 -0
- package/.codex/agents/courses-orqx.md +64 -0
- package/.codex/agents/creative-strategist.md +4 -0
- package/.codex/agents/cro-specialist.md +4 -0
- package/.codex/agents/cs-business-auditor.md +4 -0
- package/.codex/agents/cs-client-success.md +4 -0
- package/.codex/agents/cs-crm-specialist.md +4 -0
- package/.codex/agents/cs-funnel-architect.md +4 -0
- package/.codex/agents/cs-lead-generation-strategist.md +4 -0
- package/.codex/agents/cs-offer-designer.md +4 -0
- package/.codex/agents/cs-revops-analyst.md +4 -0
- package/.codex/agents/cs-sales-closer.md +4 -0
- package/.codex/agents/cs-sales-enablement.md +4 -0
- package/.codex/agents/css-motion-artist.md +4 -0
- package/.codex/agents/curriculum-designer.md +4 -0
- package/.codex/agents/cyber-chief.md +169 -0
- package/.codex/agents/cyber-orqx.md +67 -0
- package/.codex/agents/dan-harmon.md +4 -0
- package/.codex/agents/dan-mall.md +43 -0
- package/.codex/agents/data-chief.md +198 -0
- package/.codex/agents/data-engineer.md +109 -0
- package/.codex/agents/data-synthesizer.md +4 -0
- package/.codex/agents/dave-malouf.md +43 -0
- package/.codex/agents/db-sage.md +152 -0
- package/.codex/agents/deep-researcher.md +4 -0
- package/.codex/agents/derek-sivers.md +4 -0
- package/.codex/agents/design-chief.md +226 -0
- package/.codex/agents/design-orqx.md +65 -0
- package/.codex/agents/design-system.md +210 -0
- package/.codex/agents/dev.md +102 -0
- package/.codex/agents/devops.md +90 -0
- package/.codex/agents/direct-response-writer.md +4 -0
- package/.codex/agents/dx-accessibility-specialist.md +4 -0
- package/.codex/agents/dx-design-system-architect.md +4 -0
- package/.codex/agents/dx-frontend-engineer.md +4 -0
- package/.codex/agents/dx-interaction-designer.md +4 -0
- package/.codex/agents/dx-performance-engineer.md +4 -0
- package/.codex/agents/dx-ui-designer.md +4 -0
- package/.codex/agents/dx-ux-strategist.md +4 -0
- package/.codex/agents/editorial-strategist.md +4 -0
- package/.codex/agents/email-sequence-strategist.md +4 -0
- package/.codex/agents/finance-orqx.md +57 -0
- package/.codex/agents/funnel-copywriter.md +4 -0
- package/.codex/agents/ga-analytics-engineer.md +4 -0
- package/.codex/agents/ga-campaign-analyst.md +4 -0
- package/.codex/agents/ga-cro-specialist.md +4 -0
- package/.codex/agents/ga-data-analyst.md +4 -0
- package/.codex/agents/ga-growth-hacker.md +4 -0
- package/.codex/agents/ga-seo-strategist.md +4 -0
- package/.codex/agents/generative-particle-engineer.md +4 -0
- package/.codex/agents/google-ads-specialist.md +4 -0
- package/.codex/agents/growth-orqx.md +75 -0
- package/.codex/agents/headline-specialist.md +4 -0
- package/.codex/agents/hooks-architect.md +4 -0
- package/.codex/agents/incident-responder.md +4 -0
- package/.codex/agents/joseph-campbell.md +4 -0
- package/.codex/agents/kb-architect.md +4 -0
- package/.codex/agents/keith-johnstone.md +4 -0
- package/.codex/agents/kindra-hall.md +4 -0
- package/.codex/agents/launch-strategist.md +4 -0
- package/.codex/agents/legal-chief.md +199 -0
- package/.codex/agents/lesson-architect.md +4 -0
- package/.codex/agents/long-form-writer.md +4 -0
- package/.codex/agents/market-analyst.md +4 -0
- package/.codex/agents/marshall-ganz.md +4 -0
- package/.codex/agents/mcp-integrator.md +4 -0
- package/.codex/agents/meta-ads-specialist.md +4 -0
- package/.codex/agents/mind-synthesizer.md +4 -0
- package/.codex/agents/motion-choreographer.md +4 -0
- package/.codex/agents/nancy-duarte.md +4 -0
- package/.codex/agents/nano-banana-generator.md +42 -0
- package/.codex/agents/naval-ravikant.md +4 -0
- package/.codex/agents/network-security-engineer.md +4 -0
- package/.codex/agents/oren-klaff.md +4 -0
- package/.codex/agents/paidmedia-orqx.md +67 -0
- package/.codex/agents/park-howell.md +4 -0
- package/.codex/agents/patrick-lencioni.md +4 -0
- package/.codex/agents/penetration-tester.md +4 -0
- package/.codex/agents/performance-engineer.md +4 -0
- package/.codex/agents/persuasion-psychologist.md +4 -0
- package/.codex/agents/peter-thiel.md +4 -0
- package/.codex/agents/platform-specialist.md +4 -0
- package/.codex/agents/pm-creative-performance-analyst.md +4 -0
- package/.codex/agents/pm-youtube-ads-specialist.md +4 -0
- package/.codex/agents/pm.md +81 -0
- package/.codex/agents/po.md +85 -0
- package/.codex/agents/pricing-strategist.md +4 -0
- package/.codex/agents/product-orqx.md +57 -0
- package/.codex/agents/production-director.md +4 -0
- package/.codex/agents/profitability-analyst.md +4 -0
- package/.codex/agents/project-integrator.md +4 -0
- package/.codex/agents/proof-architect.md +4 -0
- package/.codex/agents/ps-client-product-manager.md +4 -0
- package/.codex/agents/ps-delivery-manager.md +4 -0
- package/.codex/agents/ps-discovery-lead.md +4 -0
- package/.codex/agents/ps-product-analyst.md +4 -0
- package/.codex/agents/ps-product-ops-specialist.md +4 -0
- package/.codex/agents/ps-product-strategist.md +4 -0
- package/.codex/agents/qa.md +98 -0
- package/.codex/agents/ray-dalio.md +4 -0
- package/.codex/agents/reid-hoffman.md +4 -0
- package/.codex/agents/research-orqx.md +67 -0
- package/.codex/agents/revenue-analyst.md +4 -0
- package/.codex/agents/roadmap-sentinel.md +4 -0
- package/.codex/agents/scroll-narrative-engineer.md +4 -0
- package/.codex/agents/shader-artist.md +4 -0
- package/.codex/agents/signal-intelligence.md +4 -0
- package/.codex/agents/simon-sinek.md +4 -0
- package/.codex/agents/sinapse-orqx.md +619 -0
- package/.codex/agents/skill-craftsman.md +4 -0
- package/.codex/agents/slide-designer.md +4 -0
- package/.codex/agents/sm.md +77 -0
- package/.codex/agents/soc-analyst.md +4 -0
- package/.codex/agents/sop-extractor.md +61 -0
- package/.codex/agents/source-hunter.md +4 -0
- package/.codex/agents/squad-assembler.md +4 -0
- package/.codex/agents/squad-chief.md +1553 -0
- package/.codex/agents/squad.md +66 -0
- package/.codex/agents/story-chief.md +180 -0
- package/.codex/agents/storytelling-orqx.md +65 -0
- package/.codex/agents/swarm-orqx.md +64 -0
- package/.codex/agents/threat-analyst.md +4 -0
- package/.codex/agents/threejs-architect.md +4 -0
- package/.codex/agents/tools-orqx.md +219 -0
- package/.codex/agents/traffic-masters-chief.md +211 -0
- package/.codex/agents/trend-forecaster.md +4 -0
- package/.codex/agents/ux-designer.md +124 -0
- package/.codex/agents/yvon-chouinard.md +4 -0
- package/.codex/instructions.md +82 -0
- package/.codex/skills/sinapse-analyst/SKILL.md +28 -0
- package/.codex/skills/sinapse-animations/SKILL.md +28 -0
- package/.codex/skills/sinapse-architect/SKILL.md +30 -0
- package/.codex/skills/sinapse-brand/SKILL.md +28 -0
- package/.codex/skills/sinapse-claude/SKILL.md +28 -0
- package/.codex/skills/sinapse-cloning/SKILL.md +28 -0
- package/.codex/skills/sinapse-commercial/SKILL.md +28 -0
- package/.codex/skills/sinapse-content/SKILL.md +28 -0
- package/.codex/skills/sinapse-copy/SKILL.md +28 -0
- package/.codex/skills/sinapse-council/SKILL.md +28 -0
- package/.codex/skills/sinapse-courses/SKILL.md +28 -0
- package/.codex/skills/sinapse-cyber/SKILL.md +28 -0
- package/.codex/skills/sinapse-data-engineer/SKILL.md +30 -0
- package/.codex/skills/sinapse-design/SKILL.md +28 -0
- package/.codex/skills/sinapse-dev/SKILL.md +30 -0
- package/.codex/skills/sinapse-devops/SKILL.md +30 -0
- package/.codex/skills/sinapse-finance/SKILL.md +28 -0
- package/.codex/skills/sinapse-growth/SKILL.md +28 -0
- package/.codex/skills/sinapse-orqx/SKILL.md +30 -0
- package/.codex/skills/sinapse-paidmedia/SKILL.md +28 -0
- package/.codex/skills/sinapse-pm/SKILL.md +30 -0
- package/.codex/skills/sinapse-po/SKILL.md +30 -0
- package/.codex/skills/sinapse-product/SKILL.md +28 -0
- package/.codex/skills/sinapse-qa/SKILL.md +30 -0
- package/.codex/skills/sinapse-research/SKILL.md +28 -0
- package/.codex/skills/sinapse-sm/SKILL.md +26 -0
- package/.codex/skills/sinapse-squad-creator/SKILL.md +30 -0
- package/.codex/skills/sinapse-storytelling/SKILL.md +28 -0
- package/.codex/skills/sinapse-swarm/SKILL.md +28 -0
- package/.codex/skills/sinapse-ux-design-expert/SKILL.md +23 -0
- package/.sinapse-ai/data/entity-registry.yaml +763 -765
- package/.sinapse-ai/development/templates/chrome-brain/knowledge-base/chrome-brain.md +161 -0
- package/.sinapse-ai/development/templates/chrome-brain/rules/chrome-brain-autoload.md +56 -0
- package/.sinapse-ai/development/templates/chrome-brain/scripts/chrome-brain-log.sh +67 -0
- package/.sinapse-ai/development/templates/chrome-brain/scripts/chrome-debug.sh +232 -0
- package/.sinapse-ai/development/templates/chrome-brain/scripts/chrome-ensure.sh +210 -0
- package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-animations.md +50 -0
- package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-brand.md +42 -0
- package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-claude.md +49 -0
- package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-cloning.md +50 -0
- package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-commercial.md +41 -0
- package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-content.md +45 -0
- package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-copy.md +44 -0
- package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-cybersecurity.md +42 -0
- package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-design.md +50 -0
- package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-growth.md +45 -0
- package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-paidmedia.md +47 -0
- package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-product.md +49 -0
- package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-research.md +41 -0
- package/.sinapse-ai/development/templates/chrome-brain/squad-integrations/squad-storytelling.md +41 -0
- package/.sinapse-ai/install-manifest.yaml +81 -5
- package/CHROME-BRAIN-INSTALL.md +93 -0
- package/README.md +28 -1
- package/bin/modules/chrome-brain-installer.js +757 -0
- package/bin/sinapse.js +18 -0
- package/install-chrome-brain.sh +1328 -0
- package/package.json +6 -1
- package/packages/installer/src/wizard/feedback.js +13 -13
- package/packages/installer/src/wizard/i18n.js +30 -0
- package/packages/sinapse-install/src/capabilities/chrome-brain.js +962 -0
- package/packages/sinapse-install/src/installer.js +60 -2
- package/sinapse/agents/sinapse-orqx.md +27 -0
|
@@ -0,0 +1,757 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chrome Brain CLI Module
|
|
3
|
+
* Provides `sinapse chrome-brain install|uninstall|status` commands
|
|
4
|
+
*
|
|
5
|
+
* Story 7.4.1: Chrome Brain Productization
|
|
6
|
+
* @module chrome-brain-installer
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const os = require('os');
|
|
14
|
+
const { execSync } = require('child_process');
|
|
15
|
+
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Constants
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
const HOME = os.homedir();
|
|
21
|
+
const SINAPSE_DIR = path.join(HOME, '.sinapse');
|
|
22
|
+
const SCRIPTS_DIR = path.join(HOME, '.local', 'bin');
|
|
23
|
+
const CLAUDE_SETTINGS = path.join(HOME, '.claude', 'settings.json');
|
|
24
|
+
const CLAUDE_JSON = path.join(HOME, '.claude.json');
|
|
25
|
+
|
|
26
|
+
const SCRIPTS = ['chrome-ensure', 'chrome-debug', 'chrome-brain-log'];
|
|
27
|
+
|
|
28
|
+
const SQUAD_INTEGRATIONS = [
|
|
29
|
+
'squad-animations', 'squad-design', 'squad-cloning', 'squad-claude',
|
|
30
|
+
'squad-paidmedia', 'squad-growth', 'squad-content', 'squad-copy',
|
|
31
|
+
'squad-research', 'squad-cybersecurity', 'squad-commercial',
|
|
32
|
+
'squad-brand', 'squad-storytelling', 'squad-product',
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
// ============================================================================
|
|
36
|
+
// Helpers
|
|
37
|
+
// ============================================================================
|
|
38
|
+
|
|
39
|
+
function green(text) { return `\x1b[32m${text}\x1b[0m`; }
|
|
40
|
+
function red(text) { return `\x1b[31m${text}\x1b[0m`; }
|
|
41
|
+
function yellow(text) { return `\x1b[33m${text}\x1b[0m`; }
|
|
42
|
+
function cyan(text) { return `\x1b[36m${text}\x1b[0m`; }
|
|
43
|
+
function bold(text) { return `\x1b[1m${text}\x1b[0m`; }
|
|
44
|
+
|
|
45
|
+
function ok(msg) { console.log(` ${green('[OK]')} ${msg}`); }
|
|
46
|
+
function fail(msg) { console.log(` ${red('[FAIL]')} ${msg}`); }
|
|
47
|
+
function warn(msg) { console.log(` ${yellow('[WARN]')} ${msg}`); }
|
|
48
|
+
function info(msg) { console.log(` ${cyan('[INFO]')} ${msg}`); }
|
|
49
|
+
function step(msg) { console.log(`\n${bold(msg)}`); }
|
|
50
|
+
|
|
51
|
+
// ============================================================================
|
|
52
|
+
// OS & Chrome Detection
|
|
53
|
+
// ============================================================================
|
|
54
|
+
|
|
55
|
+
function detectPlatform() {
|
|
56
|
+
const platform = process.platform;
|
|
57
|
+
if (platform === 'darwin') return 'macos';
|
|
58
|
+
if (platform === 'win32') return 'windows';
|
|
59
|
+
// Check WSL
|
|
60
|
+
try {
|
|
61
|
+
if (process.env.WSL_DISTRO_NAME) return 'wsl';
|
|
62
|
+
const procVersion = fs.readFileSync('/proc/version', 'utf8').toLowerCase();
|
|
63
|
+
if (procVersion.includes('microsoft') || procVersion.includes('wsl')) return 'wsl';
|
|
64
|
+
} catch { /* not WSL */ }
|
|
65
|
+
if (platform === 'linux') return 'linux';
|
|
66
|
+
return 'unknown';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function detectChrome() {
|
|
70
|
+
const platform = detectPlatform();
|
|
71
|
+
const candidates = [];
|
|
72
|
+
|
|
73
|
+
if (platform === 'macos') {
|
|
74
|
+
candidates.push('/Applications/Google Chrome.app/Contents/MacOS/Google Chrome');
|
|
75
|
+
candidates.push('/Applications/Chromium.app/Contents/MacOS/Chromium');
|
|
76
|
+
} else if (platform === 'windows') {
|
|
77
|
+
const pf = process.env.PROGRAMFILES || 'C:\\Program Files';
|
|
78
|
+
const pf86 = process.env['PROGRAMFILES(X86)'] || 'C:\\Program Files (x86)';
|
|
79
|
+
const localAppData = process.env.LOCALAPPDATA || path.join(HOME, 'AppData', 'Local');
|
|
80
|
+
candidates.push(path.join(pf, 'Google', 'Chrome', 'Application', 'chrome.exe'));
|
|
81
|
+
candidates.push(path.join(pf86, 'Google', 'Chrome', 'Application', 'chrome.exe'));
|
|
82
|
+
candidates.push(path.join(localAppData, 'Google', 'Chrome', 'Application', 'chrome.exe'));
|
|
83
|
+
} else {
|
|
84
|
+
// Linux / WSL
|
|
85
|
+
const linuxCandidates = [
|
|
86
|
+
'google-chrome', 'google-chrome-stable', 'chromium-browser', 'chromium',
|
|
87
|
+
];
|
|
88
|
+
for (const cmd of linuxCandidates) {
|
|
89
|
+
try {
|
|
90
|
+
const result = execSync(`which ${cmd} 2>/dev/null`, { encoding: 'utf8' }).trim();
|
|
91
|
+
if (result) candidates.push(result);
|
|
92
|
+
} catch { /* not found */ }
|
|
93
|
+
}
|
|
94
|
+
candidates.push('/usr/bin/google-chrome');
|
|
95
|
+
candidates.push('/usr/bin/google-chrome-stable');
|
|
96
|
+
candidates.push('/usr/bin/chromium-browser');
|
|
97
|
+
candidates.push('/usr/bin/chromium');
|
|
98
|
+
candidates.push('/snap/bin/chromium');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
for (const candidate of candidates) {
|
|
102
|
+
if (fs.existsSync(candidate)) {
|
|
103
|
+
return candidate;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ============================================================================
|
|
111
|
+
// JSON Merge (safe, no python3)
|
|
112
|
+
// ============================================================================
|
|
113
|
+
|
|
114
|
+
function readJson(filePath) {
|
|
115
|
+
try {
|
|
116
|
+
if (fs.existsSync(filePath)) {
|
|
117
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
118
|
+
}
|
|
119
|
+
} catch (error) {
|
|
120
|
+
warn(`Could not parse ${filePath}: ${error.message}`);
|
|
121
|
+
}
|
|
122
|
+
return {};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function writeJson(filePath, data) {
|
|
126
|
+
const dir = path.dirname(filePath);
|
|
127
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
128
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function mergeHooks(settingsPath, hookDefs) {
|
|
132
|
+
const settings = readJson(settingsPath);
|
|
133
|
+
if (!settings.hooks) settings.hooks = {};
|
|
134
|
+
|
|
135
|
+
for (const [hookType, hookList] of Object.entries(hookDefs)) {
|
|
136
|
+
const existing = settings.hooks[hookType] || [];
|
|
137
|
+
const newMatchers = new Set(hookList.map(h => h.matcher));
|
|
138
|
+
// Keep existing entries that don't conflict
|
|
139
|
+
const filtered = existing.filter(e => !newMatchers.has(e.matcher));
|
|
140
|
+
filtered.push(...hookList);
|
|
141
|
+
settings.hooks[hookType] = filtered;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
writeJson(settingsPath, settings);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function removeHooks(settingsPath, matchers) {
|
|
148
|
+
const settings = readJson(settingsPath);
|
|
149
|
+
if (!settings.hooks) return;
|
|
150
|
+
|
|
151
|
+
for (const hookType of Object.keys(settings.hooks)) {
|
|
152
|
+
settings.hooks[hookType] = (settings.hooks[hookType] || [])
|
|
153
|
+
.filter(e => !matchers.includes(e.matcher));
|
|
154
|
+
if (settings.hooks[hookType].length === 0) {
|
|
155
|
+
delete settings.hooks[hookType];
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (Object.keys(settings.hooks).length === 0) {
|
|
160
|
+
delete settings.hooks;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
writeJson(settingsPath, settings);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ============================================================================
|
|
167
|
+
// Script Generation (cross-platform)
|
|
168
|
+
// ============================================================================
|
|
169
|
+
|
|
170
|
+
function sanitizeChromePath(chromePath) {
|
|
171
|
+
// Validate Chrome path contains only safe characters to prevent shell injection
|
|
172
|
+
const sanitized = chromePath.replace(/\\/g, '/');
|
|
173
|
+
if (!/^[a-zA-Z0-9\s/\-_.:()\[\]]+$/.test(sanitized)) {
|
|
174
|
+
throw new Error(`Unsafe Chrome path detected: ${chromePath}`);
|
|
175
|
+
}
|
|
176
|
+
return sanitized;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function generateChromeEnsure(chromePath, platform) {
|
|
180
|
+
const safePath = sanitizeChromePath(chromePath);
|
|
181
|
+
const chromeCmd = `"${safePath}"`;
|
|
182
|
+
|
|
183
|
+
return `#!/bin/bash
|
|
184
|
+
# Chrome Brain — chrome-ensure (auto-launch)
|
|
185
|
+
# Called by PreToolUse hook before any chrome-devtools or claude-in-chrome tool
|
|
186
|
+
# Cross-platform: macOS, Linux, Windows Git Bash
|
|
187
|
+
|
|
188
|
+
PORT="\${1:-9222}"
|
|
189
|
+
CHROME_DEBUG_PROFILE="$HOME/.chrome-debug-profile"
|
|
190
|
+
CDP="http://127.0.0.1:$PORT/json/version"
|
|
191
|
+
|
|
192
|
+
# Fast path: check if already running (~50ms)
|
|
193
|
+
if curl -sf "$CDP" -o /dev/null --max-time 1 2>/dev/null; then
|
|
194
|
+
exit 0
|
|
195
|
+
fi
|
|
196
|
+
|
|
197
|
+
# Kill stale debug profile instances only (never normal Chrome)
|
|
198
|
+
pgrep -f "user-data-dir=$CHROME_DEBUG_PROFILE" 2>/dev/null | xargs kill 2>/dev/null || true
|
|
199
|
+
sleep 1
|
|
200
|
+
|
|
201
|
+
# Launch Chrome with debug flags
|
|
202
|
+
${chromeCmd} \\
|
|
203
|
+
--remote-debugging-port="$PORT" \\
|
|
204
|
+
--user-data-dir="$CHROME_DEBUG_PROFILE" \\
|
|
205
|
+
--no-first-run \\
|
|
206
|
+
&>/dev/null &
|
|
207
|
+
|
|
208
|
+
# Wait for startup (max 10 seconds)
|
|
209
|
+
for i in $(seq 1 20); do
|
|
210
|
+
if curl -sf "$CDP" -o /dev/null --max-time 1 2>/dev/null; then
|
|
211
|
+
exit 0
|
|
212
|
+
fi
|
|
213
|
+
sleep 0.5
|
|
214
|
+
done
|
|
215
|
+
|
|
216
|
+
echo "BLOCKED: Chrome debug failed to start on port $PORT. Run 'chrome-debug' manually." >&2
|
|
217
|
+
exit 1
|
|
218
|
+
`;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function generateChromeDebug(chromePath, platform) {
|
|
222
|
+
const safePath = sanitizeChromePath(chromePath);
|
|
223
|
+
const chromeCmd = `"${safePath}"`;
|
|
224
|
+
|
|
225
|
+
return `#!/bin/bash
|
|
226
|
+
# Chrome Brain — chrome-debug (manual launch)
|
|
227
|
+
# User runs this directly if auto-launch doesn't work
|
|
228
|
+
|
|
229
|
+
PORT="\${1:-9222}"
|
|
230
|
+
CHROME_DEBUG_PROFILE="$HOME/.chrome-debug-profile"
|
|
231
|
+
|
|
232
|
+
# Check if already running
|
|
233
|
+
if curl -s "http://127.0.0.1:$PORT/json/version" &>/dev/null; then
|
|
234
|
+
echo "Chrome debug already running on port $PORT"
|
|
235
|
+
exit 0
|
|
236
|
+
fi
|
|
237
|
+
|
|
238
|
+
# Kill only debug profile instances
|
|
239
|
+
pgrep -f "user-data-dir=$CHROME_DEBUG_PROFILE" 2>/dev/null | xargs kill 2>/dev/null || true
|
|
240
|
+
sleep 2
|
|
241
|
+
|
|
242
|
+
echo "Launching Chrome with remote debugging on port $PORT..."
|
|
243
|
+
|
|
244
|
+
${chromeCmd} \\
|
|
245
|
+
--remote-debugging-port="$PORT" \\
|
|
246
|
+
--user-data-dir="$CHROME_DEBUG_PROFILE" \\
|
|
247
|
+
--no-first-run \\
|
|
248
|
+
&>/dev/null &
|
|
249
|
+
|
|
250
|
+
# Wait for startup
|
|
251
|
+
for i in $(seq 1 15); do
|
|
252
|
+
if curl -s "http://127.0.0.1:$PORT/json/version" &>/dev/null; then
|
|
253
|
+
echo "Chrome ready on port $PORT"
|
|
254
|
+
exit 0
|
|
255
|
+
fi
|
|
256
|
+
sleep 1
|
|
257
|
+
done
|
|
258
|
+
|
|
259
|
+
echo "ERROR: Chrome failed to start with debugging"
|
|
260
|
+
exit 1
|
|
261
|
+
`;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function generateChromeBrainLog() {
|
|
265
|
+
return `#!/bin/bash
|
|
266
|
+
# Chrome Brain — chrome-brain-log (session logger)
|
|
267
|
+
# Called by PostToolUse hook after every chrome tool call
|
|
268
|
+
# Tracks usage and warns about screenshot limits
|
|
269
|
+
|
|
270
|
+
LOG_DIR="$HOME/.chrome-brain"
|
|
271
|
+
TODAY=$(date +%Y%m%d)
|
|
272
|
+
LOG_FILE="$LOG_DIR/session-$TODAY.log"
|
|
273
|
+
COUNTER_FILE="$LOG_DIR/.screenshot-count"
|
|
274
|
+
COUNTER_DATE_FILE="$LOG_DIR/.screenshot-date"
|
|
275
|
+
mkdir -p "$LOG_DIR"
|
|
276
|
+
|
|
277
|
+
# Reset counter daily
|
|
278
|
+
LAST_DATE=$(cat "$COUNTER_DATE_FILE" 2>/dev/null || echo "")
|
|
279
|
+
if [ "$LAST_DATE" != "$TODAY" ]; then
|
|
280
|
+
echo "0" > "$COUNTER_FILE"
|
|
281
|
+
echo "$TODAY" > "$COUNTER_DATE_FILE"
|
|
282
|
+
fi
|
|
283
|
+
|
|
284
|
+
TOOL_NAME="\${HOOK_TOOL_NAME:-unknown}"
|
|
285
|
+
TIMESTAMP=$(date +%H:%M:%S)
|
|
286
|
+
|
|
287
|
+
echo "$TIMESTAMP $TOOL_NAME" >> "$LOG_FILE"
|
|
288
|
+
|
|
289
|
+
if echo "$TOOL_NAME" | grep -qE "take_screenshot|take_snapshot"; then
|
|
290
|
+
COUNT=$(cat "$COUNTER_FILE" 2>/dev/null || echo 0)
|
|
291
|
+
COUNT=$((COUNT + 1))
|
|
292
|
+
echo "$COUNT" > "$COUNTER_FILE"
|
|
293
|
+
|
|
294
|
+
if [ "$COUNT" -eq 12 ]; then
|
|
295
|
+
echo "WARNING: 12 screenshots in this session. Consider saving state and rotating." >&2
|
|
296
|
+
elif [ "$COUNT" -ge 15 ]; then
|
|
297
|
+
echo "CRITICAL: 15+ screenshots. Session at risk of exceeding 20MB API limit. Save state NOW." >&2
|
|
298
|
+
fi
|
|
299
|
+
fi
|
|
300
|
+
|
|
301
|
+
exit 0
|
|
302
|
+
`;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ============================================================================
|
|
306
|
+
// Install
|
|
307
|
+
// ============================================================================
|
|
308
|
+
|
|
309
|
+
function installScripts(chromePath, platform) {
|
|
310
|
+
step('Installing scripts...');
|
|
311
|
+
|
|
312
|
+
const scriptsDir = platform === 'windows'
|
|
313
|
+
? path.join(SINAPSE_DIR, 'bin')
|
|
314
|
+
: SCRIPTS_DIR;
|
|
315
|
+
|
|
316
|
+
fs.mkdirSync(scriptsDir, { recursive: true });
|
|
317
|
+
|
|
318
|
+
const scripts = {
|
|
319
|
+
'chrome-ensure': generateChromeEnsure(chromePath, platform),
|
|
320
|
+
'chrome-debug': generateChromeDebug(chromePath, platform),
|
|
321
|
+
'chrome-brain-log': generateChromeBrainLog(),
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
for (const [name, content] of Object.entries(scripts)) {
|
|
325
|
+
const scriptPath = path.join(scriptsDir, name);
|
|
326
|
+
fs.writeFileSync(scriptPath, content, { encoding: 'utf8', mode: 0o755 });
|
|
327
|
+
try {
|
|
328
|
+
fs.chmodSync(scriptPath, 0o755);
|
|
329
|
+
} catch { /* Windows doesn't support chmod */ }
|
|
330
|
+
ok(`${name} created at ${scriptPath}`);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Check PATH
|
|
334
|
+
const pathDirs = (process.env.PATH || '').split(path.delimiter);
|
|
335
|
+
if (!pathDirs.includes(scriptsDir)) {
|
|
336
|
+
warn(`${scriptsDir} not in PATH. Add to your shell profile: export PATH="${scriptsDir}:$PATH"`);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return scriptsDir;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function installHooks() {
|
|
343
|
+
step('Merging hooks into ~/.claude/settings.json...');
|
|
344
|
+
|
|
345
|
+
const hookDefs = {
|
|
346
|
+
PreToolUse: [
|
|
347
|
+
{ matcher: 'mcp__chrome-devtools__*', hooks: [{ type: 'command', command: 'chrome-ensure' }] },
|
|
348
|
+
{ matcher: 'mcp__claude-in-chrome__*', hooks: [{ type: 'command', command: 'chrome-ensure' }] },
|
|
349
|
+
],
|
|
350
|
+
PostToolUse: [
|
|
351
|
+
{ matcher: 'mcp__chrome-devtools__*', hooks: [{ type: 'command', command: 'chrome-brain-log' }] },
|
|
352
|
+
{ matcher: 'mcp__claude-in-chrome__*', hooks: [{ type: 'command', command: 'chrome-brain-log' }] },
|
|
353
|
+
],
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
try {
|
|
357
|
+
mergeHooks(CLAUDE_SETTINGS, hookDefs);
|
|
358
|
+
ok('Hooks merged into ~/.claude/settings.json');
|
|
359
|
+
} catch (error) {
|
|
360
|
+
fail(`Failed to merge hooks: ${error.message}`);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Also create standalone hooks in ~/.sinapse/.claude/settings.json
|
|
364
|
+
const sinapseSettings = path.join(SINAPSE_DIR, '.claude', 'settings.json');
|
|
365
|
+
try {
|
|
366
|
+
writeJson(sinapseSettings, { hooks: hookDefs });
|
|
367
|
+
ok('Standalone hooks at ~/.sinapse/.claude/settings.json');
|
|
368
|
+
} catch (error) {
|
|
369
|
+
warn(`Could not create standalone hooks: ${error.message}`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function installMcp(platform) {
|
|
374
|
+
step('Configuring Chrome DevTools MCP...');
|
|
375
|
+
|
|
376
|
+
const config = readJson(CLAUDE_JSON);
|
|
377
|
+
if (!config.mcpServers) config.mcpServers = {};
|
|
378
|
+
|
|
379
|
+
if (platform === 'windows') {
|
|
380
|
+
config.mcpServers['chrome-devtools'] = {
|
|
381
|
+
command: 'cmd',
|
|
382
|
+
args: ['/c', 'npx', '-y', 'chrome-devtools-mcp@latest', '--browser-url=http://127.0.0.1:9222'],
|
|
383
|
+
};
|
|
384
|
+
} else {
|
|
385
|
+
config.mcpServers['chrome-devtools'] = {
|
|
386
|
+
command: 'npx',
|
|
387
|
+
args: ['chrome-devtools-mcp@latest', '--browser-url=http://127.0.0.1:9222'],
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
try {
|
|
392
|
+
writeJson(CLAUDE_JSON, config);
|
|
393
|
+
ok('Chrome DevTools MCP configured in ~/.claude.json');
|
|
394
|
+
} catch (error) {
|
|
395
|
+
fail(`Failed to configure MCP: ${error.message}`);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function installKnowledgeBase() {
|
|
400
|
+
step('Installing knowledge base and rules...');
|
|
401
|
+
|
|
402
|
+
// Find template directory (inside the npm package)
|
|
403
|
+
const templateDir = findTemplateDir();
|
|
404
|
+
if (!templateDir) {
|
|
405
|
+
warn('Template directory not found — creating minimal KB files');
|
|
406
|
+
createMinimalKB();
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Copy autoload rule
|
|
411
|
+
const rulesSrc = path.join(templateDir, 'rules', 'chrome-brain-autoload.md');
|
|
412
|
+
const rulesDest = path.join(SINAPSE_DIR, '.claude', 'rules', 'chrome-brain-autoload.md');
|
|
413
|
+
copyFile(rulesSrc, rulesDest, 'chrome-brain-autoload.md rule');
|
|
414
|
+
|
|
415
|
+
// Copy master KB
|
|
416
|
+
const kbSrc = path.join(templateDir, 'knowledge-base', 'chrome-brain.md');
|
|
417
|
+
const kbDest = path.join(SINAPSE_DIR, 'sinapse', 'knowledge-base', 'chrome-brain.md');
|
|
418
|
+
copyFile(kbSrc, kbDest, 'master KB chrome-brain.md');
|
|
419
|
+
|
|
420
|
+
// Copy squad integration files
|
|
421
|
+
const integrationsDir = path.join(templateDir, 'squad-integrations');
|
|
422
|
+
if (fs.existsSync(integrationsDir)) {
|
|
423
|
+
for (const squad of SQUAD_INTEGRATIONS) {
|
|
424
|
+
const src = path.join(integrationsDir, `${squad}.md`);
|
|
425
|
+
const dest = path.join(SINAPSE_DIR, squad, 'knowledge-base', 'chrome-brain-integration.md');
|
|
426
|
+
copyFile(src, dest, `${squad}/chrome-brain-integration.md`);
|
|
427
|
+
}
|
|
428
|
+
} else {
|
|
429
|
+
warn('Squad integrations template directory not found');
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function findTemplateDir() {
|
|
434
|
+
// Try multiple locations
|
|
435
|
+
const candidates = [
|
|
436
|
+
// When running from npm package (npx sinapse-ai)
|
|
437
|
+
path.join(__dirname, '..', '..', '.sinapse-ai', 'development', 'templates', 'chrome-brain'),
|
|
438
|
+
// When running from git repo
|
|
439
|
+
path.join(process.cwd(), '.sinapse-ai', 'development', 'templates', 'chrome-brain'),
|
|
440
|
+
// When installed as devDependency
|
|
441
|
+
path.join(process.cwd(), 'node_modules', 'sinapse-ai', '.sinapse-ai', 'development', 'templates', 'chrome-brain'),
|
|
442
|
+
];
|
|
443
|
+
|
|
444
|
+
for (const candidate of candidates) {
|
|
445
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function copyFile(src, dest, label) {
|
|
452
|
+
try {
|
|
453
|
+
if (fs.existsSync(src)) {
|
|
454
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
455
|
+
fs.copyFileSync(src, dest);
|
|
456
|
+
ok(label);
|
|
457
|
+
} else {
|
|
458
|
+
warn(`Template not found: ${src}`);
|
|
459
|
+
}
|
|
460
|
+
} catch (error) {
|
|
461
|
+
fail(`Failed to copy ${label}: ${error.message}`);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function createMinimalKB() {
|
|
466
|
+
// Create minimal chrome-brain.md if templates not available
|
|
467
|
+
const kbDir = path.join(SINAPSE_DIR, 'sinapse', 'knowledge-base');
|
|
468
|
+
fs.mkdirSync(kbDir, { recursive: true });
|
|
469
|
+
const kbPath = path.join(kbDir, 'chrome-brain.md');
|
|
470
|
+
if (!fs.existsSync(kbPath)) {
|
|
471
|
+
fs.writeFileSync(kbPath, [
|
|
472
|
+
'# Chrome Brain — Browser Automation Capability',
|
|
473
|
+
'',
|
|
474
|
+
'> Cross-squad capability for browser automation.',
|
|
475
|
+
'> Auto-activated. NSN Mode always on.',
|
|
476
|
+
'',
|
|
477
|
+
'## Learnings Log',
|
|
478
|
+
'',
|
|
479
|
+
'> Updated automatically when NSN Mode resolves new barriers.',
|
|
480
|
+
'',
|
|
481
|
+
].join('\n'), 'utf8');
|
|
482
|
+
ok('Minimal chrome-brain.md created');
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// ============================================================================
|
|
487
|
+
// Uninstall
|
|
488
|
+
// ============================================================================
|
|
489
|
+
|
|
490
|
+
function uninstallChromeBrain() {
|
|
491
|
+
console.log(`\n${bold(cyan('Chrome Brain — Uninstall'))}\n`);
|
|
492
|
+
|
|
493
|
+
let removed = 0;
|
|
494
|
+
|
|
495
|
+
// Remove scripts
|
|
496
|
+
step('Removing scripts...');
|
|
497
|
+
for (const name of SCRIPTS) {
|
|
498
|
+
for (const dir of [SCRIPTS_DIR, path.join(SINAPSE_DIR, 'bin')]) {
|
|
499
|
+
const scriptPath = path.join(dir, name);
|
|
500
|
+
if (fs.existsSync(scriptPath)) {
|
|
501
|
+
fs.unlinkSync(scriptPath);
|
|
502
|
+
ok(`Removed ${scriptPath}`);
|
|
503
|
+
removed++;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Remove hooks
|
|
509
|
+
step('Removing hooks from settings...');
|
|
510
|
+
const matchers = [
|
|
511
|
+
'mcp__chrome-devtools__*',
|
|
512
|
+
'mcp__claude-in-chrome__*',
|
|
513
|
+
];
|
|
514
|
+
|
|
515
|
+
if (fs.existsSync(CLAUDE_SETTINGS)) {
|
|
516
|
+
removeHooks(CLAUDE_SETTINGS, matchers);
|
|
517
|
+
ok('Hooks removed from ~/.claude/settings.json');
|
|
518
|
+
removed++;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const sinapseSettings = path.join(SINAPSE_DIR, '.claude', 'settings.json');
|
|
522
|
+
if (fs.existsSync(sinapseSettings)) {
|
|
523
|
+
fs.unlinkSync(sinapseSettings);
|
|
524
|
+
ok('Removed ~/.sinapse/.claude/settings.json');
|
|
525
|
+
removed++;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// Remove MCP config
|
|
529
|
+
step('Removing MCP configuration...');
|
|
530
|
+
if (fs.existsSync(CLAUDE_JSON)) {
|
|
531
|
+
const config = readJson(CLAUDE_JSON);
|
|
532
|
+
if (config.mcpServers && config.mcpServers['chrome-devtools']) {
|
|
533
|
+
delete config.mcpServers['chrome-devtools'];
|
|
534
|
+
writeJson(CLAUDE_JSON, config);
|
|
535
|
+
ok('Removed chrome-devtools from ~/.claude.json');
|
|
536
|
+
removed++;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// Remove KB files
|
|
541
|
+
step('Removing knowledge base files...');
|
|
542
|
+
const kbFiles = [
|
|
543
|
+
path.join(SINAPSE_DIR, '.claude', 'rules', 'chrome-brain-autoload.md'),
|
|
544
|
+
path.join(SINAPSE_DIR, 'sinapse', 'knowledge-base', 'chrome-brain.md'),
|
|
545
|
+
];
|
|
546
|
+
|
|
547
|
+
for (const file of kbFiles) {
|
|
548
|
+
if (fs.existsSync(file)) {
|
|
549
|
+
fs.unlinkSync(file);
|
|
550
|
+
ok(`Removed ${path.basename(file)}`);
|
|
551
|
+
removed++;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
for (const squad of SQUAD_INTEGRATIONS) {
|
|
556
|
+
const file = path.join(SINAPSE_DIR, squad, 'knowledge-base', 'chrome-brain-integration.md');
|
|
557
|
+
if (fs.existsSync(file)) {
|
|
558
|
+
fs.unlinkSync(file);
|
|
559
|
+
removed++;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
ok(`Removed ${SQUAD_INTEGRATIONS.length} squad integration files`);
|
|
563
|
+
|
|
564
|
+
console.log(`\n${bold('Uninstall complete.')} Removed ${removed} items.`);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// ============================================================================
|
|
568
|
+
// Status
|
|
569
|
+
// ============================================================================
|
|
570
|
+
|
|
571
|
+
function getChromeBrainStatus() {
|
|
572
|
+
console.log(`\n${bold(cyan('Chrome Brain — Status'))}\n`);
|
|
573
|
+
|
|
574
|
+
let installed = 0;
|
|
575
|
+
let total = 0;
|
|
576
|
+
|
|
577
|
+
// Chrome detection
|
|
578
|
+
total++;
|
|
579
|
+
const chromePath = detectChrome();
|
|
580
|
+
if (chromePath) {
|
|
581
|
+
ok(`Chrome found: ${chromePath}`);
|
|
582
|
+
installed++;
|
|
583
|
+
} else {
|
|
584
|
+
fail('Chrome not found');
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// Scripts
|
|
588
|
+
for (const name of SCRIPTS) {
|
|
589
|
+
total++;
|
|
590
|
+
const scriptPath = path.join(SCRIPTS_DIR, name);
|
|
591
|
+
const altPath = path.join(SINAPSE_DIR, 'bin', name);
|
|
592
|
+
if (fs.existsSync(scriptPath) || fs.existsSync(altPath)) {
|
|
593
|
+
ok(`Script: ${name}`);
|
|
594
|
+
installed++;
|
|
595
|
+
} else {
|
|
596
|
+
fail(`Script: ${name} not found`);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// Hooks
|
|
601
|
+
total++;
|
|
602
|
+
if (fs.existsSync(CLAUDE_SETTINGS)) {
|
|
603
|
+
const settings = readJson(CLAUDE_SETTINGS);
|
|
604
|
+
const preHooks = (settings.hooks?.PreToolUse || []).map(h => h.matcher);
|
|
605
|
+
if (preHooks.includes('mcp__chrome-devtools__*')) {
|
|
606
|
+
ok('Hooks: PreToolUse + PostToolUse configured');
|
|
607
|
+
installed++;
|
|
608
|
+
} else {
|
|
609
|
+
fail('Hooks: not configured');
|
|
610
|
+
}
|
|
611
|
+
} else {
|
|
612
|
+
fail('Hooks: ~/.claude/settings.json not found');
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// MCP
|
|
616
|
+
total++;
|
|
617
|
+
if (fs.existsSync(CLAUDE_JSON)) {
|
|
618
|
+
const config = readJson(CLAUDE_JSON);
|
|
619
|
+
if (config.mcpServers?.['chrome-devtools']) {
|
|
620
|
+
ok('MCP: chrome-devtools configured');
|
|
621
|
+
installed++;
|
|
622
|
+
} else {
|
|
623
|
+
fail('MCP: chrome-devtools not configured');
|
|
624
|
+
}
|
|
625
|
+
} else {
|
|
626
|
+
fail('MCP: ~/.claude.json not found');
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// KB
|
|
630
|
+
total++;
|
|
631
|
+
const kbPath = path.join(SINAPSE_DIR, 'sinapse', 'knowledge-base', 'chrome-brain.md');
|
|
632
|
+
if (fs.existsSync(kbPath)) {
|
|
633
|
+
ok('KB: chrome-brain.md');
|
|
634
|
+
installed++;
|
|
635
|
+
} else {
|
|
636
|
+
fail('KB: chrome-brain.md not found');
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// Squad integrations
|
|
640
|
+
total++;
|
|
641
|
+
let squadCount = 0;
|
|
642
|
+
for (const squad of SQUAD_INTEGRATIONS) {
|
|
643
|
+
const file = path.join(SINAPSE_DIR, squad, 'knowledge-base', 'chrome-brain-integration.md');
|
|
644
|
+
if (fs.existsSync(file)) squadCount++;
|
|
645
|
+
}
|
|
646
|
+
if (squadCount === SQUAD_INTEGRATIONS.length) {
|
|
647
|
+
ok(`Squad integrations: ${squadCount}/${SQUAD_INTEGRATIONS.length}`);
|
|
648
|
+
installed++;
|
|
649
|
+
} else if (squadCount > 0) {
|
|
650
|
+
warn(`Squad integrations: ${squadCount}/${SQUAD_INTEGRATIONS.length}`);
|
|
651
|
+
} else {
|
|
652
|
+
fail('Squad integrations: none found');
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// Summary
|
|
656
|
+
console.log(`\n${bold('Summary:')} ${installed}/${total} checks passed`);
|
|
657
|
+
|
|
658
|
+
if (installed === total) {
|
|
659
|
+
console.log(green('\nChrome Brain is fully installed and operational.'));
|
|
660
|
+
} else if (installed > 0) {
|
|
661
|
+
console.log(yellow('\nChrome Brain is partially installed. Run `sinapse chrome-brain install` to complete.'));
|
|
662
|
+
} else {
|
|
663
|
+
console.log(red('\nChrome Brain is not installed. Run `sinapse chrome-brain install` to set up.'));
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
return { installed, total, chromePath };
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// ============================================================================
|
|
670
|
+
// Main Entry Point
|
|
671
|
+
// ============================================================================
|
|
672
|
+
|
|
673
|
+
async function runChromeBrain(subArgs) {
|
|
674
|
+
const subCommand = subArgs[0];
|
|
675
|
+
|
|
676
|
+
switch (subCommand) {
|
|
677
|
+
case 'install': {
|
|
678
|
+
console.log('');
|
|
679
|
+
console.log(bold(cyan(' Chrome Brain — SINAPSE Install')));
|
|
680
|
+
console.log(cyan(' Browser Automation Capability for All Squads'));
|
|
681
|
+
console.log('');
|
|
682
|
+
|
|
683
|
+
const platform = detectPlatform();
|
|
684
|
+
info(`Platform: ${platform}`);
|
|
685
|
+
|
|
686
|
+
// Step 1: Detect Chrome
|
|
687
|
+
step('Step 1/5 — Detecting Chrome...');
|
|
688
|
+
const chromePath = detectChrome();
|
|
689
|
+
if (!chromePath) {
|
|
690
|
+
fail('Google Chrome not found on this system');
|
|
691
|
+
console.log('\n Install Chrome from https://google.com/chrome and try again.');
|
|
692
|
+
process.exit(1);
|
|
693
|
+
}
|
|
694
|
+
ok(`Chrome found: ${chromePath}`);
|
|
695
|
+
|
|
696
|
+
// Step 2: Install scripts
|
|
697
|
+
step('Step 2/5 — Installing scripts...');
|
|
698
|
+
installScripts(chromePath, platform);
|
|
699
|
+
|
|
700
|
+
// Step 3: Configure hooks
|
|
701
|
+
step('Step 3/5 — Configuring hooks...');
|
|
702
|
+
installHooks();
|
|
703
|
+
|
|
704
|
+
// Step 4: Configure MCP
|
|
705
|
+
step('Step 4/5 — Configuring MCP...');
|
|
706
|
+
installMcp(platform);
|
|
707
|
+
|
|
708
|
+
// Step 5: Install KB
|
|
709
|
+
step('Step 5/5 — Installing knowledge base...');
|
|
710
|
+
installKnowledgeBase();
|
|
711
|
+
|
|
712
|
+
// Summary
|
|
713
|
+
console.log(`\n${bold(green('Chrome Brain installed successfully!'))}`);
|
|
714
|
+
console.log(`\n ${cyan('To test:')}`);
|
|
715
|
+
console.log(' chrome-debug # Launch Chrome with debug port');
|
|
716
|
+
console.log(' chrome-ensure # Auto-launch (used by hooks)');
|
|
717
|
+
console.log(`\n ${cyan('In Claude Code:')}`);
|
|
718
|
+
console.log(' "abre o site google.com" # Chrome Brain auto-activates');
|
|
719
|
+
break;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
case 'uninstall':
|
|
723
|
+
uninstallChromeBrain();
|
|
724
|
+
break;
|
|
725
|
+
|
|
726
|
+
case 'status':
|
|
727
|
+
getChromeBrainStatus();
|
|
728
|
+
break;
|
|
729
|
+
|
|
730
|
+
default:
|
|
731
|
+
console.log(`
|
|
732
|
+
${bold('sinapse chrome-brain')} — Browser Automation Capability
|
|
733
|
+
|
|
734
|
+
${bold('USAGE:')}
|
|
735
|
+
sinapse chrome-brain install Install Chrome Brain (scripts, hooks, MCP, KB)
|
|
736
|
+
sinapse chrome-brain uninstall Remove Chrome Brain completely
|
|
737
|
+
sinapse chrome-brain status Check installation status
|
|
738
|
+
|
|
739
|
+
${bold('WHAT IT DOES:')}
|
|
740
|
+
Gives ALL SINAPSE agents the ability to control Chrome in real-time:
|
|
741
|
+
navigate sites, clone pages, fill forms, audit performance, extract data.
|
|
742
|
+
Auto-activates when needed. No manual commands required after install.
|
|
743
|
+
`);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
module.exports = {
|
|
748
|
+
runChromeBrain,
|
|
749
|
+
detectChrome,
|
|
750
|
+
detectPlatform,
|
|
751
|
+
getChromeBrainStatus,
|
|
752
|
+
installScripts,
|
|
753
|
+
installHooks,
|
|
754
|
+
installMcp,
|
|
755
|
+
installKnowledgeBase,
|
|
756
|
+
uninstallChromeBrain,
|
|
757
|
+
};
|