brosh 0.2.2 → 0.2.4
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/README.github.md +169 -0
- package/README.md +18 -141
- package/README.npm.md +58 -0
- package/dist/lib.d.ts +1 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +1 -1
- package/dist/lib.js.map +1 -1
- package/dist/terminal/index.d.ts +1 -1
- package/dist/terminal/index.d.ts.map +1 -1
- package/dist/terminal/index.js +1 -1
- package/dist/terminal/index.js.map +1 -1
- package/dist/terminal/session.d.ts +14 -1
- package/dist/terminal/session.d.ts.map +1 -1
- package/dist/terminal/session.js +263 -78
- package/dist/terminal/session.js.map +1 -1
- package/package.json +7 -4
- package/packages/desktop-electron/build/afterInstall-linux.sh +4 -0
- package/packages/desktop-electron/build/afterPack.cjs +29 -19
- package/packages/desktop-electron/build/entitlements.mac.inherit.plist +14 -0
- package/packages/desktop-electron/build/entitlements.mac.plist +16 -0
- package/packages/desktop-electron/package-lock.json +666 -165
- package/packages/desktop-electron/package.json +53 -14
- package/packages/desktop-electron/scripts/bundle-main.mjs +97 -0
- package/packages/desktop-electron/scripts/bytecode-compiler.cjs +3 -0
- package/packages/desktop-electron/scripts/fix-dev-entitlements.js +56 -0
- package/packages/desktop-electron/vite.config.ts +13 -0
- package/packaging/aur/.SRCINFO +20 -0
- package/packaging/aur/PKGBUILD +26 -0
- package/vendor/xterm-headless-5.5.0.tgz +0 -0
- package/vendor/xterm-xterm-5.5.0.tgz +0 -0
- package/website/CNAME +1 -0
- package/website/assets/images/.gitkeep +0 -0
- package/website/assets/videos/.gitkeep +0 -0
- package/website/css/styles.css +735 -0
- package/website/gpg.key +37 -0
- package/website/index.html +314 -0
- package/website/install.sh.asc +16 -0
- package/website/js/main.js +293 -0
- package/website/rpm/brosh.repo +6 -0
- package/website/uninstall.sh +10 -0
- package/packages/desktop-electron/tests/main/error-triage/buildTriagePrompt.test.ts +0 -133
- package/packages/desktop-electron/tests/main/error-triage/parseTriageResponse.test.ts +0 -123
package/website/gpg.key
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
2
|
+
|
|
3
|
+
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
|
|
36
|
+
=o7Ve
|
|
37
|
+
-----END PGP PUBLIC KEY BLOCK-----
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>brosh - Built for Claude coders</title>
|
|
7
|
+
<meta name="description" content="A modern terminal emulator with built-in AI integration via MCP. Natural language detection, split panes, Git sidebar, sandbox mode, and more.">
|
|
8
|
+
|
|
9
|
+
<!-- Open Graph -->
|
|
10
|
+
<meta property="og:type" content="website">
|
|
11
|
+
<meta property="og:title" content="brosh - Built for Claude coders">
|
|
12
|
+
<meta property="og:description" content="A modern terminal emulator with built-in AI integration via MCP. Built for Claude coders.">
|
|
13
|
+
<meta property="og:image" content="assets/images/brosh_startscreen.png">
|
|
14
|
+
|
|
15
|
+
<!-- Twitter Card -->
|
|
16
|
+
<meta name="twitter:card" content="summary_large_image">
|
|
17
|
+
<meta name="twitter:title" content="brosh - Built for Claude coders">
|
|
18
|
+
<meta name="twitter:description" content="A modern terminal emulator with built-in AI integration via MCP. Built for Claude coders.">
|
|
19
|
+
<meta name="twitter:image" content="assets/images/brosh_startscreen.png">
|
|
20
|
+
|
|
21
|
+
<!-- Favicon -->
|
|
22
|
+
<link rel="icon" type="image/png" sizes="32x32" href="assets/images/32x32.png">
|
|
23
|
+
<link rel="icon" type="image/png" sizes="16x16" href="assets/images/16x16.png">
|
|
24
|
+
<link rel="icon" type="image/png" sizes="256x256" href="assets/images/256x256.png">
|
|
25
|
+
<link rel="apple-touch-icon" sizes="512x512" href="assets/images/512x512.png">
|
|
26
|
+
|
|
27
|
+
<!-- Fonts -->
|
|
28
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
29
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
30
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap">
|
|
31
|
+
|
|
32
|
+
<link rel="stylesheet" href="css/styles.css">
|
|
33
|
+
</head>
|
|
34
|
+
<body>
|
|
35
|
+
<!-- Sticky Nav -->
|
|
36
|
+
<nav class="nav" id="nav">
|
|
37
|
+
<div class="nav-inner">
|
|
38
|
+
<a href="#" class="nav-logo">
|
|
39
|
+
<img src="assets/images/brosh_logo.svg" alt="brosh" height="32">
|
|
40
|
+
</a>
|
|
41
|
+
<button class="nav-toggle" id="nav-toggle" aria-label="Toggle menu">
|
|
42
|
+
<span></span>
|
|
43
|
+
<span></span>
|
|
44
|
+
<span></span>
|
|
45
|
+
</button>
|
|
46
|
+
<div class="nav-links" id="nav-links">
|
|
47
|
+
<a href="#features">Features</a>
|
|
48
|
+
<a href="https://github.com/elleryfamilia/brosh" target="_blank" rel="noopener">GitHub</a>
|
|
49
|
+
<a href="#download" class="nav-download" id="nav-download-btn">Download for Mac</a>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</nav>
|
|
53
|
+
|
|
54
|
+
<!-- Hero -->
|
|
55
|
+
<section class="hero" id="hero">
|
|
56
|
+
<div class="hero-content">
|
|
57
|
+
<h1 class="hero-headline">Built for Claude.<br>The missing piece.</h1>
|
|
58
|
+
<p class="hero-tagline">A smart terminal that brings clarity and speed to your workflow.</p>
|
|
59
|
+
<div class="hero-cta">
|
|
60
|
+
<a href="#download" class="btn btn-primary" id="hero-download-btn">Download for Mac</a>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="hero-install" id="hero-install">
|
|
63
|
+
<code>brew install --cask elleryfamilia/brosh/brosh</code>
|
|
64
|
+
<button class="copy-btn" aria-label="Copy to clipboard" data-copy="brew install --cask elleryfamilia/brosh/brosh">
|
|
65
|
+
<svg class="copy-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
66
|
+
<svg class="check-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
|
|
67
|
+
</button>
|
|
68
|
+
</div>
|
|
69
|
+
<a href="#download" class="hero-other-platforms">Other platforms</a>
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<!-- Video Player / Screenshot Showcase -->
|
|
73
|
+
<div class="showcase">
|
|
74
|
+
<div class="showcase-window">
|
|
75
|
+
<div class="window-frame">
|
|
76
|
+
<div class="window-titlebar">
|
|
77
|
+
<span class="window-dot red"></span>
|
|
78
|
+
<span class="window-dot yellow"></span>
|
|
79
|
+
<span class="window-dot green"></span>
|
|
80
|
+
</div>
|
|
81
|
+
<div class="window-content">
|
|
82
|
+
<div class="showcase-panel active" data-panel="nlp">
|
|
83
|
+
<video class="showcase-video" data-src="assets/videos/nlp.mp4" muted loop playsinline></video>
|
|
84
|
+
<img class="showcase-img" src="assets/images/terminal_chat.png" alt="Natural language detection in brosh">
|
|
85
|
+
</div>
|
|
86
|
+
<div class="showcase-panel" data-panel="panes">
|
|
87
|
+
<video class="showcase-video" data-src="assets/videos/panes.mp4" muted loop playsinline></video>
|
|
88
|
+
<img class="showcase-img" src="assets/images/brosh_startscreen.png" alt="Split panes and tabs">
|
|
89
|
+
</div>
|
|
90
|
+
<div class="showcase-panel" data-panel="git">
|
|
91
|
+
<video class="showcase-video" data-src="assets/videos/git.mp4" muted loop playsinline></video>
|
|
92
|
+
<img class="showcase-img" src="assets/images/git_sidebar.png" alt="Git sidebar and diff view">
|
|
93
|
+
</div>
|
|
94
|
+
<div class="showcase-panel" data-panel="sandbox">
|
|
95
|
+
<video class="showcase-video" data-src="assets/videos/sandbox.mp4" muted loop playsinline></video>
|
|
96
|
+
<img class="showcase-img" src="assets/images/sandbox_selection2.png" alt="Sandbox mode">
|
|
97
|
+
</div>
|
|
98
|
+
<div class="showcase-panel" data-panel="mcp">
|
|
99
|
+
<video class="showcase-video" data-src="assets/videos/mcp.mp4" muted loop playsinline></video>
|
|
100
|
+
<img class="showcase-img" src="assets/images/mcp-enabled2.png" alt="MCP integration">
|
|
101
|
+
</div>
|
|
102
|
+
<div class="showcase-panel" data-panel="recording">
|
|
103
|
+
<video class="showcase-video" data-src="assets/videos/recording.mp4" muted loop playsinline></video>
|
|
104
|
+
<img class="showcase-img" src="assets/images/brosh_startscreen.png" alt="Session recording">
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
<div class="showcase-tabs">
|
|
110
|
+
<button class="showcase-tab active" data-tab="nlp">Natural Language</button>
|
|
111
|
+
<button class="showcase-tab" data-tab="panes">Split Panes</button>
|
|
112
|
+
<button class="showcase-tab" data-tab="git">Git Sidebar</button>
|
|
113
|
+
<button class="showcase-tab" data-tab="sandbox">Sandbox</button>
|
|
114
|
+
<button class="showcase-tab" data-tab="mcp">MCP</button>
|
|
115
|
+
<button class="showcase-tab" data-tab="recording">Recording</button>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
</section>
|
|
119
|
+
|
|
120
|
+
<!-- Features -->
|
|
121
|
+
<section class="features" id="features">
|
|
122
|
+
<!-- AI-Native -->
|
|
123
|
+
<div class="feature-row reveal">
|
|
124
|
+
<div class="feature-text">
|
|
125
|
+
<h2>AI-Native</h2>
|
|
126
|
+
<p>brosh detects natural language input and routes it to your AI model — no prefix needed. Zero-config MCP server connects Claude Code to your terminal automatically. Switch between models, continue conversations in Claude, and let AI work alongside your shell.</p>
|
|
127
|
+
<ul class="feature-list">
|
|
128
|
+
<li>Natural language detection with ML classifier</li>
|
|
129
|
+
<li>Zero-config MCP server for Claude Code</li>
|
|
130
|
+
<li>Model switching and "Continue in Claude"</li>
|
|
131
|
+
<li>AI-aware terminal context</li>
|
|
132
|
+
</ul>
|
|
133
|
+
</div>
|
|
134
|
+
<div class="feature-media">
|
|
135
|
+
<div class="window-frame">
|
|
136
|
+
<div class="window-titlebar">
|
|
137
|
+
<span class="window-dot red"></span>
|
|
138
|
+
<span class="window-dot yellow"></span>
|
|
139
|
+
<span class="window-dot green"></span>
|
|
140
|
+
</div>
|
|
141
|
+
<div class="window-content">
|
|
142
|
+
<img src="assets/images/terminal_chat.png" alt="AI-native terminal chat" loading="lazy">
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
<!-- Developer Tools -->
|
|
149
|
+
<div class="feature-row reverse reveal">
|
|
150
|
+
<div class="feature-text">
|
|
151
|
+
<h2>Developer Tools</h2>
|
|
152
|
+
<p>Built-in Git sidebar shows your repository status, branch graph, and staged changes at a glance. Monaco-powered diff viewer lets you review changes without leaving the terminal. Record and replay terminal sessions for debugging or sharing.</p>
|
|
153
|
+
<ul class="feature-list">
|
|
154
|
+
<li>Git sidebar with branch graph</li>
|
|
155
|
+
<li>Monaco diff editor</li>
|
|
156
|
+
<li>Session recording and playback</li>
|
|
157
|
+
<li>Smart status bar</li>
|
|
158
|
+
</ul>
|
|
159
|
+
</div>
|
|
160
|
+
<div class="feature-media">
|
|
161
|
+
<div class="window-frame">
|
|
162
|
+
<div class="window-titlebar">
|
|
163
|
+
<span class="window-dot red"></span>
|
|
164
|
+
<span class="window-dot yellow"></span>
|
|
165
|
+
<span class="window-dot green"></span>
|
|
166
|
+
</div>
|
|
167
|
+
<div class="window-content">
|
|
168
|
+
<img src="assets/images/git_sidebar.png" alt="Git sidebar and diff view" loading="lazy">
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
|
|
174
|
+
<!-- Customizable -->
|
|
175
|
+
<div class="feature-row reveal">
|
|
176
|
+
<div class="feature-text">
|
|
177
|
+
<h2>Customizable</h2>
|
|
178
|
+
<p>Choose from 9 built-in themes and 25+ developer fonts. Split your workspace into panes and tabs. Adjust opacity, font size, and cursor style. Make the terminal yours.</p>
|
|
179
|
+
<ul class="feature-list">
|
|
180
|
+
<li>9 themes including dark and light</li>
|
|
181
|
+
<li>25+ curated developer fonts</li>
|
|
182
|
+
<li>Split panes and tabbed sessions</li>
|
|
183
|
+
<li>Adjustable opacity and styling</li>
|
|
184
|
+
</ul>
|
|
185
|
+
</div>
|
|
186
|
+
<div class="feature-media">
|
|
187
|
+
<div class="window-frame">
|
|
188
|
+
<div class="window-titlebar">
|
|
189
|
+
<span class="window-dot red"></span>
|
|
190
|
+
<span class="window-dot yellow"></span>
|
|
191
|
+
<span class="window-dot green"></span>
|
|
192
|
+
</div>
|
|
193
|
+
<div class="window-content">
|
|
194
|
+
<img src="assets/images/brosh_startscreen.png" alt="brosh customization" loading="lazy">
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
|
|
200
|
+
<!-- Secure -->
|
|
201
|
+
<div class="feature-row reverse reveal">
|
|
202
|
+
<div class="feature-text">
|
|
203
|
+
<h2>Secure</h2>
|
|
204
|
+
<p>Sandbox mode restricts AI agent access to only the directories you allow. On macOS, brosh uses Seatbelt profiles; on Linux, bubblewrap. Per-path permissions give you full control over what AI can read and write.</p>
|
|
205
|
+
<ul class="feature-list">
|
|
206
|
+
<li>Sandbox mode for AI agents</li>
|
|
207
|
+
<li>Per-path permission controls</li>
|
|
208
|
+
<li>macOS Seatbelt integration</li>
|
|
209
|
+
<li>Linux bubblewrap support</li>
|
|
210
|
+
</ul>
|
|
211
|
+
</div>
|
|
212
|
+
<div class="feature-media">
|
|
213
|
+
<div class="window-frame">
|
|
214
|
+
<div class="window-titlebar">
|
|
215
|
+
<span class="window-dot red"></span>
|
|
216
|
+
<span class="window-dot yellow"></span>
|
|
217
|
+
<span class="window-dot green"></span>
|
|
218
|
+
</div>
|
|
219
|
+
<div class="window-content">
|
|
220
|
+
<img src="assets/images/sandbox_selection2.png" alt="Sandbox mode configuration" loading="lazy">
|
|
221
|
+
</div>
|
|
222
|
+
</div>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
</section>
|
|
226
|
+
|
|
227
|
+
<!-- MCP Setup -->
|
|
228
|
+
<section class="mcp-setup" id="mcp-setup">
|
|
229
|
+
<div class="mcp-setup-inner reveal">
|
|
230
|
+
<h2>MCP Integration</h2>
|
|
231
|
+
<p>Add to your Claude Code MCP settings and start working.</p>
|
|
232
|
+
<div class="terminal-block">
|
|
233
|
+
<div class="terminal-titlebar">
|
|
234
|
+
<span class="window-dot red"></span>
|
|
235
|
+
<span class="window-dot yellow"></span>
|
|
236
|
+
<span class="window-dot green"></span>
|
|
237
|
+
<span class="terminal-title">~/.claude/settings.json</span>
|
|
238
|
+
</div>
|
|
239
|
+
<pre class="terminal-code"><code>{
|
|
240
|
+
"mcpServers": {
|
|
241
|
+
"brosh": {
|
|
242
|
+
"command": "npx",
|
|
243
|
+
"args": ["-y", "brosh"]
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}</code></pre>
|
|
247
|
+
</div>
|
|
248
|
+
</div>
|
|
249
|
+
</section>
|
|
250
|
+
|
|
251
|
+
<!-- Download -->
|
|
252
|
+
<section class="download" id="download">
|
|
253
|
+
<div class="download-inner reveal">
|
|
254
|
+
<h2>Download brosh</h2>
|
|
255
|
+
<p class="download-version" id="download-version"></p>
|
|
256
|
+
|
|
257
|
+
<!-- Primary download -->
|
|
258
|
+
<div class="download-primary" id="download-primary">
|
|
259
|
+
<!-- Populated by JS based on detected OS -->
|
|
260
|
+
</div>
|
|
261
|
+
|
|
262
|
+
<!-- Alternative installs -->
|
|
263
|
+
<div class="download-alternatives">
|
|
264
|
+
<h3>Other install methods</h3>
|
|
265
|
+
<div class="install-grid">
|
|
266
|
+
<div class="install-card">
|
|
267
|
+
<h4>Homebrew</h4>
|
|
268
|
+
<div class="code-inline">
|
|
269
|
+
<code>brew install --cask brosh</code>
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
<div class="install-card">
|
|
273
|
+
<h4>Linux (Ubuntu/Debian)</h4>
|
|
274
|
+
<div class="code-inline">
|
|
275
|
+
<code>curl -fsSL https://bro.sh/install.sh | sudo bash</code>
|
|
276
|
+
</div>
|
|
277
|
+
</div>
|
|
278
|
+
<div class="install-card">
|
|
279
|
+
<h4>AUR (Arch Linux)</h4>
|
|
280
|
+
<div class="code-inline">
|
|
281
|
+
<code>yay -S brosh-desktop-bin</code>
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
</div>
|
|
285
|
+
|
|
286
|
+
<div class="download-direct">
|
|
287
|
+
<h3>Direct downloads</h3>
|
|
288
|
+
<div class="direct-links" id="direct-links">
|
|
289
|
+
<!-- Populated by JS -->
|
|
290
|
+
</div>
|
|
291
|
+
</div>
|
|
292
|
+
</div>
|
|
293
|
+
</div>
|
|
294
|
+
</section>
|
|
295
|
+
|
|
296
|
+
<!-- Footer -->
|
|
297
|
+
<footer class="footer">
|
|
298
|
+
<div class="footer-inner">
|
|
299
|
+
<div class="footer-brand">
|
|
300
|
+
<img src="assets/images/brosh_logo.svg" alt="brosh" height="24">
|
|
301
|
+
<span class="footer-copyright">© 2025 Ellery Familia. MIT License.</span>
|
|
302
|
+
</div>
|
|
303
|
+
<div class="footer-links">
|
|
304
|
+
<a href="https://github.com/elleryfamilia/brosh" target="_blank" rel="noopener">GitHub</a>
|
|
305
|
+
<a href="https://www.npmjs.com/package/brosh" target="_blank" rel="noopener">npm</a>
|
|
306
|
+
<a href="https://github.com/elleryfamilia/brosh/releases" target="_blank" rel="noopener">Releases</a>
|
|
307
|
+
<a href="https://github.com/elleryfamilia/brosh#readme" target="_blank" rel="noopener">Docs</a>
|
|
308
|
+
</div>
|
|
309
|
+
</div>
|
|
310
|
+
</footer>
|
|
311
|
+
|
|
312
|
+
<script src="js/main.js"></script>
|
|
313
|
+
</body>
|
|
314
|
+
</html>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
-----BEGIN PGP SIGNATURE-----
|
|
2
|
+
|
|
3
|
+
iQIzBAABCgAdFiEEX8WeGtXPO7P8xoFftW8bjWv2UfkFAmnIj5sACgkQtW8bjWv2
|
|
4
|
+
UfmuDhAAoDnJsbAl6WXAz1k1nnn+bom3MDLSy9qpkpE3v2R9V+IHeUAgpuykNCVM
|
|
5
|
+
HuBxdZz5pu9odN9YrGO+wxr7HNH+tFmfjMmHoPaQVolN9lfgtgGk8YtLBj7BrkoT
|
|
6
|
+
6Pmp4JE81om18bowJWhwrd5LlkNXc69+jmJe2iJ8Po8uPqWd4JKqW6PQkeewaVri
|
|
7
|
+
la/pi01tIiM0jsVT9UZSxPdOwt0HScCMFV6DfP3PmAMNM2GgzfhkWsInYJURWGyb
|
|
8
|
+
7cZ5eWpXOwfQVmvpY3kkZDIIyTArEeyWK7zd61j6XxJMcLoO+smEFL82YuNaEikq
|
|
9
|
+
Qo3ocnrQ6Q64QkfcV21lHV1A+2uN/hABAITMqxpYd//4a5tWWh3GGtGTMx+VzfVQ
|
|
10
|
+
ZIm+vQhpYeMgcOJtKaGl0dCStzvdtsW6hoOcnQ5fWg6hjRu4XdaotoSqedGFpyq+
|
|
11
|
+
efF0euzlGk+T7Y98UWhsyhnG6Ke7jOq0BuhVCJP6XFW0ya/sd90Cj5pEWpBl/mEl
|
|
12
|
+
2dj8D2KOXQDhtN9wWF+kFyuEMBnJbu4znNMsILr3/qXRIUtTN2YA1nIcr68ZsaFh
|
|
13
|
+
PEssrPovFfarZpuuEWFoJVEJm+rsrmRDJVjCjzHnMNhqT38AEXd0sg9r4kNAfkG8
|
|
14
|
+
QntnacAm+TwEKCU7EsX8g5GX8NtIziEsEsJLxbEqwEpn1Ozh2fc=
|
|
15
|
+
=Cqev
|
|
16
|
+
-----END PGP SIGNATURE-----
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
// brosh landing page scripts
|
|
2
|
+
|
|
3
|
+
(function () {
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
var REPO = 'elleryfamilia/brosh';
|
|
7
|
+
var RELEASE_API = 'https://api.github.com/repos/' + REPO + '/releases/latest';
|
|
8
|
+
|
|
9
|
+
// ---- Copy buttons ----
|
|
10
|
+
document.querySelectorAll('.copy-btn').forEach(function (btn) {
|
|
11
|
+
btn.addEventListener('click', function () {
|
|
12
|
+
var text = this.getAttribute('data-copy');
|
|
13
|
+
navigator.clipboard.writeText(text).then(function () {
|
|
14
|
+
btn.classList.add('copied');
|
|
15
|
+
setTimeout(function () { btn.classList.remove('copied'); }, 2000);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// ---- Nav scroll effect ----
|
|
21
|
+
var nav = document.getElementById('nav');
|
|
22
|
+
function updateNav() {
|
|
23
|
+
nav.classList.toggle('scrolled', window.scrollY > 20);
|
|
24
|
+
}
|
|
25
|
+
window.addEventListener('scroll', updateNav, { passive: true });
|
|
26
|
+
updateNav();
|
|
27
|
+
|
|
28
|
+
// ---- Mobile hamburger ----
|
|
29
|
+
var toggle = document.getElementById('nav-toggle');
|
|
30
|
+
var links = document.getElementById('nav-links');
|
|
31
|
+
toggle.addEventListener('click', function () {
|
|
32
|
+
toggle.classList.toggle('open');
|
|
33
|
+
links.classList.toggle('open');
|
|
34
|
+
});
|
|
35
|
+
links.querySelectorAll('a').forEach(function (a) {
|
|
36
|
+
a.addEventListener('click', function () {
|
|
37
|
+
toggle.classList.remove('open');
|
|
38
|
+
links.classList.remove('open');
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// ---- Showcase tabs ----
|
|
43
|
+
var tabs = document.querySelectorAll('.showcase-tab');
|
|
44
|
+
var panels = document.querySelectorAll('.showcase-panel');
|
|
45
|
+
|
|
46
|
+
tabs.forEach(function (tab) {
|
|
47
|
+
tab.addEventListener('click', function () {
|
|
48
|
+
var target = this.getAttribute('data-tab');
|
|
49
|
+
tabs.forEach(function (t) { t.classList.remove('active'); });
|
|
50
|
+
panels.forEach(function (p) { p.classList.remove('active'); });
|
|
51
|
+
this.classList.add('active');
|
|
52
|
+
var panel = document.querySelector('[data-panel="' + target + '"]');
|
|
53
|
+
if (panel) {
|
|
54
|
+
panel.classList.add('active');
|
|
55
|
+
tryLoadVideo(panel);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
function tryLoadVideo(panel) {
|
|
61
|
+
var video = panel.querySelector('.showcase-video');
|
|
62
|
+
if (!video || video.classList.contains('loaded') || video.classList.contains('failed')) return;
|
|
63
|
+
var src = video.getAttribute('data-src');
|
|
64
|
+
if (!src) return;
|
|
65
|
+
|
|
66
|
+
fetch(src, { method: 'HEAD' }).then(function (res) {
|
|
67
|
+
if (res.ok) {
|
|
68
|
+
video.src = src;
|
|
69
|
+
video.addEventListener('loadeddata', function () {
|
|
70
|
+
video.classList.add('loaded');
|
|
71
|
+
video.play().catch(function () {});
|
|
72
|
+
}, { once: true });
|
|
73
|
+
video.load();
|
|
74
|
+
} else {
|
|
75
|
+
video.classList.add('failed');
|
|
76
|
+
}
|
|
77
|
+
}).catch(function () {
|
|
78
|
+
video.classList.add('failed');
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
var activePanel = document.querySelector('.showcase-panel.active');
|
|
83
|
+
if (activePanel) tryLoadVideo(activePanel);
|
|
84
|
+
|
|
85
|
+
// ---- Scroll reveal ----
|
|
86
|
+
var prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
87
|
+
if (!prefersReduced) {
|
|
88
|
+
var reveals = document.querySelectorAll('.reveal');
|
|
89
|
+
var observer = new IntersectionObserver(function (entries) {
|
|
90
|
+
entries.forEach(function (entry) {
|
|
91
|
+
if (entry.isIntersecting) {
|
|
92
|
+
entry.target.classList.add('visible');
|
|
93
|
+
observer.unobserve(entry.target);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}, { threshold: 0.15 });
|
|
97
|
+
reveals.forEach(function (el) { observer.observe(el); });
|
|
98
|
+
} else {
|
|
99
|
+
document.querySelectorAll('.reveal').forEach(function (el) {
|
|
100
|
+
el.classList.add('visible');
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ---- Hide brew install for non-macOS immediately ----
|
|
105
|
+
(function () {
|
|
106
|
+
var ua = navigator.userAgent || '';
|
|
107
|
+
var platform = (navigator.userAgentData && navigator.userAgentData.platform) || navigator.platform || '';
|
|
108
|
+
var isMac = /macOS/i.test(platform) || /Mac/i.test(platform) || /Mac/i.test(ua);
|
|
109
|
+
if (!isMac) {
|
|
110
|
+
var el = document.getElementById('hero-install');
|
|
111
|
+
if (el) el.style.display = 'none';
|
|
112
|
+
}
|
|
113
|
+
})();
|
|
114
|
+
|
|
115
|
+
// ---- OS Detection ----
|
|
116
|
+
function detectOS() {
|
|
117
|
+
var ua = navigator.userAgent;
|
|
118
|
+
var platform = navigator.platform || '';
|
|
119
|
+
|
|
120
|
+
if (navigator.userAgentData) {
|
|
121
|
+
var p = navigator.userAgentData.platform || '';
|
|
122
|
+
if (p === 'macOS') return { os: 'macos', arch: guessArch() };
|
|
123
|
+
if (p === 'Linux') return { os: 'linux', arch: 'x64' };
|
|
124
|
+
if (p === 'Windows') return { os: 'windows', arch: 'x64' };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (/Mac/i.test(platform) || /Mac/i.test(ua)) return { os: 'macos', arch: guessArch() };
|
|
128
|
+
if (/Linux/i.test(platform) || /Linux/i.test(ua)) return { os: 'linux', arch: 'x64' };
|
|
129
|
+
if (/Win/i.test(platform) || /Win/i.test(ua)) return { os: 'windows', arch: 'x64' };
|
|
130
|
+
|
|
131
|
+
return { os: 'unknown', arch: 'x64' };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function guessArch() {
|
|
135
|
+
try {
|
|
136
|
+
var canvas = document.createElement('canvas');
|
|
137
|
+
var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
|
|
138
|
+
if (gl) {
|
|
139
|
+
var dbg = gl.getExtension('WEBGL_debug_renderer_info');
|
|
140
|
+
if (dbg) {
|
|
141
|
+
var renderer = gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL) || '';
|
|
142
|
+
if (/Apple M/i.test(renderer) || /Apple GPU/i.test(renderer)) {
|
|
143
|
+
return 'arm64';
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
} catch (e) {}
|
|
148
|
+
return 'arm64'; // Default to arm64 for modern Macs
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ---- Helper: create element with attributes ----
|
|
152
|
+
function createEl(tag, attrs, textContent) {
|
|
153
|
+
var el = document.createElement(tag);
|
|
154
|
+
if (attrs) {
|
|
155
|
+
Object.keys(attrs).forEach(function (key) {
|
|
156
|
+
if (key === 'className') {
|
|
157
|
+
el.className = attrs[key];
|
|
158
|
+
} else {
|
|
159
|
+
el.setAttribute(key, attrs[key]);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
if (textContent) el.textContent = textContent;
|
|
164
|
+
return el;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ---- Release info + downloads ----
|
|
168
|
+
function fetchRelease() {
|
|
169
|
+
var cached = sessionStorage.getItem('brosh_release');
|
|
170
|
+
if (cached) {
|
|
171
|
+
try {
|
|
172
|
+
renderDownloads(JSON.parse(cached));
|
|
173
|
+
return;
|
|
174
|
+
} catch (e) {}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
fetch(RELEASE_API)
|
|
178
|
+
.then(function (r) { return r.json(); })
|
|
179
|
+
.then(function (data) {
|
|
180
|
+
if (data.tag_name) {
|
|
181
|
+
var release = {
|
|
182
|
+
version: data.tag_name.replace(/^v/, ''),
|
|
183
|
+
tag: data.tag_name,
|
|
184
|
+
assets: (data.assets || []).map(function (a) {
|
|
185
|
+
return { name: a.name, url: a.browser_download_url };
|
|
186
|
+
})
|
|
187
|
+
};
|
|
188
|
+
sessionStorage.setItem('brosh_release', JSON.stringify(release));
|
|
189
|
+
renderDownloads(release);
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
.catch(function () {
|
|
193
|
+
renderDownloads(null);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function renderDownloads(release) {
|
|
198
|
+
var detected = detectOS();
|
|
199
|
+
var versionEl = document.getElementById('download-version');
|
|
200
|
+
var primaryEl = document.getElementById('download-primary');
|
|
201
|
+
var directEl = document.getElementById('direct-links');
|
|
202
|
+
var heroBtn = document.getElementById('hero-download-btn');
|
|
203
|
+
var navBtn = document.getElementById('nav-download-btn');
|
|
204
|
+
var heroInstall = document.getElementById('hero-install');
|
|
205
|
+
|
|
206
|
+
if (release && versionEl) {
|
|
207
|
+
versionEl.textContent = 'Latest: v' + release.version;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function findAsset(pattern) {
|
|
211
|
+
if (!release) return null;
|
|
212
|
+
for (var i = 0; i < release.assets.length; i++) {
|
|
213
|
+
if (pattern.test(release.assets[i].name)) {
|
|
214
|
+
return release.assets[i].url;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
var macArm = findAsset(/arm64.*\.dmg$/);
|
|
221
|
+
var macIntel = findAsset(/x64.*\.dmg$/) || findAsset(/amd64.*\.dmg$/);
|
|
222
|
+
var linuxAmd = findAsset(/amd64.*\.deb$/);
|
|
223
|
+
var linuxArm = findAsset(/arm64.*\.deb$/);
|
|
224
|
+
|
|
225
|
+
// Clear existing content
|
|
226
|
+
while (primaryEl.firstChild) primaryEl.removeChild(primaryEl.firstChild);
|
|
227
|
+
|
|
228
|
+
function setDownloadLink(btn, url, text) {
|
|
229
|
+
if (!btn) return;
|
|
230
|
+
btn.href = url;
|
|
231
|
+
if (text) btn.textContent = text;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (detected.os === 'macos') {
|
|
235
|
+
var dmgUrl = detected.arch === 'arm64' ? (macArm || macIntel) : (macIntel || macArm);
|
|
236
|
+
var chipLabel = detected.arch === 'arm64' ? 'Apple Silicon' : 'Intel';
|
|
237
|
+
var label = 'Download for Mac' + (dmgUrl ? ' (' + chipLabel + ')' : '');
|
|
238
|
+
var url = dmgUrl || 'https://github.com/' + REPO + '/releases/latest';
|
|
239
|
+
primaryEl.appendChild(createEl('a', {
|
|
240
|
+
href: url,
|
|
241
|
+
className: 'btn btn-primary'
|
|
242
|
+
}, label));
|
|
243
|
+
setDownloadLink(heroBtn, url, 'Download for Mac');
|
|
244
|
+
setDownloadLink(navBtn, url, 'Download for Mac');
|
|
245
|
+
} else if (detected.os === 'linux') {
|
|
246
|
+
primaryEl.appendChild(createEl('div', {
|
|
247
|
+
className: 'download-command'
|
|
248
|
+
}, 'curl -fsSL https://bro.sh/install.sh | sudo bash'));
|
|
249
|
+
setDownloadLink(heroBtn, '#download', 'Install on Linux');
|
|
250
|
+
setDownloadLink(navBtn, '#download', 'Install on Linux');
|
|
251
|
+
if (heroInstall) heroInstall.style.display = 'none';
|
|
252
|
+
} else {
|
|
253
|
+
var fallbackUrl = 'https://github.com/' + REPO + '/releases/latest';
|
|
254
|
+
primaryEl.appendChild(createEl('a', {
|
|
255
|
+
href: fallbackUrl,
|
|
256
|
+
className: 'btn btn-primary'
|
|
257
|
+
}, 'Download'));
|
|
258
|
+
setDownloadLink(heroBtn, fallbackUrl);
|
|
259
|
+
setDownloadLink(navBtn, fallbackUrl);
|
|
260
|
+
if (heroInstall) heroInstall.style.display = 'none';
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Direct download links
|
|
264
|
+
if (directEl && release) {
|
|
265
|
+
while (directEl.firstChild) directEl.removeChild(directEl.firstChild);
|
|
266
|
+
var allLinks = [
|
|
267
|
+
{ label: 'macOS (Apple Silicon) .dmg', url: macArm },
|
|
268
|
+
{ label: 'macOS (Intel) .dmg', url: macIntel },
|
|
269
|
+
{ label: 'Linux amd64 .deb', url: linuxAmd },
|
|
270
|
+
{ label: 'Linux arm64 .deb', url: linuxArm }
|
|
271
|
+
];
|
|
272
|
+
allLinks.forEach(function (link) {
|
|
273
|
+
if (link.url) {
|
|
274
|
+
directEl.appendChild(createEl('a', { href: link.url }, link.label));
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
fetchRelease();
|
|
281
|
+
|
|
282
|
+
// Async high-entropy arch detection (Chromium)
|
|
283
|
+
if (navigator.userAgentData && navigator.userAgentData.getHighEntropyValues) {
|
|
284
|
+
navigator.userAgentData.getHighEntropyValues(['architecture']).then(function (data) {
|
|
285
|
+
if (data.architecture === 'arm') {
|
|
286
|
+
var cached = sessionStorage.getItem('brosh_release');
|
|
287
|
+
if (cached) {
|
|
288
|
+
try { renderDownloads(JSON.parse(cached)); } catch (e) {}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}).catch(function () {});
|
|
292
|
+
}
|
|
293
|
+
})();
|