feat: replace all emojis with high-resolution SVG Octicons across web UI

husteno-o committed 1 months ago
a236240
1 parent d2a4024
commit a236240
4 files changed
+276 -93
β–Όapps/web/src/app.ts
+77-57
1
-// DevPulse Interactive Landing Page Controller
1
+// DevPulse Interactive Landing Page Controller (Strictly SVG Icons, Zero Emojis)
2
+import { icons } from "./icons.js";
2
3
3
4
export interface SimState {
4
5
activeTab: string;
12
13
repoTab: "overview",
13
14
};
14
15
15
-// Clipboard copy helper
16
+// Clipboard copy helper with animated SVG checkmark
16
17
export function copyText(text: string, triggerBtn?: HTMLElement) {
17
18
navigator.clipboard.writeText(text).then(() => {
18
19
if (triggerBtn) {
19
20
const originalHtml = triggerBtn.innerHTML;
20
21
triggerBtn.innerHTML = `
21
- <svg width="14" height="14" viewBox="0 0 16 16" fill="#3fb950">
22
- <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/>
23
- </svg>
24
- <span style="color: #3fb950; font-weight: 600;">Copied!</span>
22
+ ${icons.check(14, "#3fb950")}
23
+ <span style="color: #3fb950; font-weight: 600;">Copied</span>
25
24
`;
26
25
setTimeout(() => {
27
26
triggerBtn.innerHTML = originalHtml;
33
32
// Simulator views
34
33
const tabTemplates: Record<string, () => string> = {
35
34
pr: () => {
36
- let statusBadge = `<span class="status-tag status-tag-green">🟒 Ready to merge</span>`;
37
- let mergeButtonHtml = `<button class="discord-btn discord-btn-primary" id="sim-btn-merge">Merge into main</button>`;
35
+ let statusBadge = `<span class="status-tag status-tag-green">${icons.checkCircle(14, "#3fb950")} Ready to merge</span>`;
36
+ let mergeButtonHtml = `<button class="discord-btn discord-btn-primary" id="sim-btn-merge">${icons.gitMerge(14, "#ffffff")} Merge into main</button>`;
38
37
39
38
if (state.prStatus === "approved") {
40
- statusBadge = `<span class="status-tag status-tag-green">βœ… Approved by you</span>`;
39
+ statusBadge = `<span class="status-tag status-tag-green">${icons.checkCircle(14, "#3fb950")} Approved by you</span>`;
41
40
} else if (state.prStatus === "changes_requested") {
42
- statusBadge = `<span class="status-tag" style="background: rgba(248,81,73,0.15); color: #f85149; border: 1px solid rgba(248,81,73,0.3)">⚠️ Changes Requested</span>`;
41
+ statusBadge = `<span class="status-tag" style="background: rgba(248,81,73,0.15); color: #f85149; border: 1px solid rgba(248,81,73,0.3)">${icons.alertTriangle(14, "#f85149")} Changes Requested</span>`;
43
42
} else if (state.prStatus === "merged") {
44
- statusBadge = `<span class="status-tag status-tag-purple">🟣 Merged into main (commit #9a8f2c)</span>`;
45
- mergeButtonHtml = `<button class="discord-btn discord-btn-disabled" disabled>Merged</button>`;
43
+ statusBadge = `<span class="status-tag status-tag-purple">${icons.gitMerge(14, "#a371f7")} Merged into main (commit #9a8f2c)</span>`;
44
+ mergeButtonHtml = `<button class="discord-btn discord-btn-disabled" disabled>${icons.gitMerge(14, "#8b949e")} Merged</button>`;
46
45
}
47
46
48
47
return `
49
48
<div class="discord-message">
50
49
<div class="discord-avatar">
51
- <svg viewBox="0 0 16 16"><path d="M5 3.254V3.25v.004a.75.75 0 1 1 0-.004Zm1.5 0a2.25 2.25 0 1 0-3 2.122V8.75a2.25 2.25 0 0 0 1.5 2.122v.378a2.25 2.25 0 1 0 1.5 0v-.378a2.25 2.25 0 0 0 1.5-2.122V5.376A2.25 2.25 0 0 0 6.5 3.254Z"/></svg>
50
+ ${icons.gitPullRequest(22, "#ffffff")}
52
51
</div>
53
52
<div class="discord-content">
54
53
<div class="discord-header">
60
59
<div class="discord-embed" style="border-left-color: ${state.prStatus === "merged" ? "#a371f7" : "#2ea043"}">
61
60
<div class="embed-author">
62
61
<span>vercel/next.js</span>
63
- <span>β€’</span>
62
+ <span>&bull;</span>
64
63
<span>Pull Request #142</span>
65
64
</div>
66
65
<div class="embed-title">
68
67
</div>
69
68
<div class="embed-desc">
70
69
${statusBadge}
71
- Author: <strong>@timneutkens</strong> β€’ Target: <code>canary β¬… feature/route-cache</code>
72
- Files Changed: <strong>14</strong> β€’ <span style="color: #3fb950">+482</span> <span style="color: #f85149">βˆ’193</span>
70
+ Author: <strong>@timneutkens</strong> &bull; Target: <code>canary &larr; feature/route-cache</code>
71
+ Files Changed: <strong>14</strong> &bull; <span style="color: #3fb950">+482</span> <span style="color: #f85149">&minus;193</span>
73
72
</div>
74
73
<div class="embed-grid">
75
74
<div>
76
75
<div class="embed-field-name">CI Status</div>
77
- <div class="embed-field-value">βœ… 12/12 Checks Passing</div>
76
+ <div class="embed-field-value">${icons.checkCircle(14, "#3fb950")} 12/12 Checks Passing</div>
78
77
</div>
79
78
<div>
80
79
<div class="embed-field-name">Reviews</div>
90
89
</div>
91
90
</div>
92
91
<div class="discord-action-row">
93
- <button class="discord-btn discord-btn-success" id="sim-btn-approve">Approve</button>
94
- <button class="discord-btn discord-btn-danger" id="sim-btn-changes">Request Changes</button>
92
+ <button class="discord-btn discord-btn-success" id="sim-btn-approve">${icons.check(14, "#ffffff")} Approve</button>
93
+ <button class="discord-btn discord-btn-danger" id="sim-btn-changes">${icons.x(14, "#ffffff")} Request Changes</button>
95
94
${mergeButtonHtml}
96
- <button class="discord-btn" onclick="window.open('https://github.com', '_blank')">Open GitHub β†—</button>
95
+ <button class="discord-btn" onclick="window.open('https://github.com', '_blank')">Open GitHub ${icons.externalLink(12, "#ffffff")}</button>
97
96
</div>
98
97
</div>
99
98
</div>
105
104
return `
106
105
<div class="discord-message">
107
106
<div class="discord-avatar">
108
- <svg viewBox="0 0 16 16"><path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8ZM5 12.25a.25.25 0 0 1 .25-.25H12v1.5H5.25a.25.25 0 0 1-.25-.25Z"/></svg>
107
+ ${icons.repo(22, "#ffffff")}
109
108
</div>
110
109
<div class="discord-content">
111
110
<div class="discord-header">
118
117
<div class="embed-author">Repository Intelligence</div>
119
118
<div class="embed-title">vercel/next.js</div>
120
119
<div class="embed-desc">
121
- The React Framework for the Web. Used by top engineering teams worldwide.
120
+ The React Framework for the Web. Used by production engineering teams worldwide.
122
121
<strong>Health Score: 96 / 100</strong> [β– β– β– β– β– β– β– β– β– β–‘]
123
122
</div>
124
123
<div class="embed-grid">
125
124
<div>
126
- <div class="embed-field-name">Stars / Forks</div>
127
- <div class="embed-field-value">β˜… 124,510 β€’ β‘‚ 26,840</div>
125
+ <div class="embed-field-name">Stars &amp; Forks</div>
126
+ <div class="embed-field-value">${icons.star(14, "#e3b341")} 124,510 &bull; ${icons.repoForked(14, "#8b949e")} 26,840</div>
128
127
</div>
129
128
<div>
130
129
<div class="embed-field-name">Open Issues / PRs</div>
131
- <div class="embed-field-value">Issue: 412 β€’ PR: 89</div>
130
+ <div class="embed-field-value">Issues: 412 &bull; PRs: 89</div>
132
131
</div>
133
132
<div>
134
133
<div class="embed-field-name">License / Branch</div>
135
- <div class="embed-field-value">MIT β€’ canary</div>
134
+ <div class="embed-field-value">MIT &bull; canary</div>
136
135
</div>
137
136
<div>
138
- <div class="embed-field-name">30d Star Velocity</div>
137
+ <div class="embed-field-name">30-Day Velocity</div>
139
138
<div class="embed-field-value"><span style="color:#3fb950">+1,840 stars</span> (+1.5%)</div>
140
139
</div>
141
140
</div>
156
155
return `
157
156
<div class="discord-message">
158
157
<div class="discord-avatar">
159
- <svg viewBox="0 0 16 16"><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"/></svg>
158
+ ${icons.actions(22, "#ffffff")}
160
159
</div>
161
160
<div class="discord-content">
162
161
<div class="discord-header">
167
166
<div class="command-echo">/actions repo:vercel/next.js branch:canary</div>
168
167
<div class="discord-embed" style="border-left-color: #2ea043">
169
168
<div class="embed-author">GitHub Actions CI/CD Pipeline</div>
170
- <div class="embed-title">canary β€’ Run #4,892 Passed</div>
169
+ <div class="embed-title">canary &bull; Run #4,892 Passed</div>
171
170
<div class="embed-desc">Triggered by <strong>@leerob</strong> via push on commit <code>3a91e4f</code></div>
172
171
<div class="embed-code-block">canary (commit 3a91e4f)
173
-β”œβ”€β”€ Unit Tests (Node 20 & 22) βœ… Passing (1m 42s)
174
-β”œβ”€β”€ Turbopack Integration E2E βœ… Passing (4m 15s)
175
-β”œβ”€β”€ Edge Runtime Compatibility βœ… Passing (52s)
176
-β”œβ”€β”€ Security Scanning & Audit βœ… Passing (38s)
177
-└── Production Bundle Analyzer βœ… Passing (1m 04s)</div>
172
+|-- Unit Tests (Node 20 & 22) [Passing] (1m 42s)
173
+|-- Turbopack Integration E2E [Passing] (4m 15s)
174
+|-- Edge Runtime Compatibility [Passing] (52s)
175
+|-- Security Scanning & Audit [Passing] (38s)
176
+\-- Production Bundle Analyzer [Passing] (1m 04s)</div>
178
177
<div class="discord-action-row">
179
- <button class="discord-btn" id="sim-btn-rerun">Rerun All Jobs</button>
178
+ <button class="discord-btn" id="sim-btn-rerun">${icons.sync(14, "#ffffff")} Rerun All Jobs</button>
180
179
<button class="discord-btn discord-btn-danger" id="sim-btn-cancel" disabled>Cancel</button>
181
- <button class="discord-btn" onclick="window.open('https://github.com', '_blank')">View Workflow Run β†—</button>
180
+ <button class="discord-btn" onclick="window.open('https://github.com', '_blank')">View Workflow Run ${icons.externalLink(12, "#ffffff")}</button>
182
181
</div>
183
182
</div>
184
183
</div>
190
189
return `
191
190
<div class="discord-message">
192
191
<div class="discord-avatar">
193
- <svg viewBox="0 0 16 16"><path d="M11.5 7a4.499 4.499 0 1 1-8.998 0A4.499 4.499 0 0 1 11.5 7Zm-.82 4.74a6 6 0 1 0-1.06 1.06l3.04 3.04a.75.75 0 1 0 1.06-1.06l-3.04-3.04Z"/></svg>
192
+ ${icons.investigate(22, "#ffffff")}
194
193
</div>
195
194
<div class="discord-content">
196
195
<div class="discord-header">
201
200
<div class="command-echo">/investigate pr:142 repo:vercel/next.js</div>
202
201
<div class="discord-embed" style="border-left-color: #a371f7">
203
202
<div class="embed-author">Lifecycle Investigation Engine</div>
204
- <div class="embed-title">Full End-to-End Development Trace</div>
205
- <div class="embed-desc">Chronological lifecycle trace from original bug report to published version:</div>
203
+ <div class="embed-title">Full Development Trace</div>
204
+ <div class="embed-desc">Chronological lifecycle trace from originating issue to published version:</div>
206
205
<div class="embed-code-block">1. Issue Created: #892 "Hydration mismatch in nested parallel routes" by @alex (Sep 1)
207
206
2. Branch Created: feature/route-cache (Sep 2)
208
207
3. Commit Added: 8f3b12a "fix: reconcile router slot metadata" by @timneutkens
212
211
7. Merged: Merged into canary by @timneutkens (Sep 3)
213
212
8. Shipped In: v15.2.0-canary.18 (Sep 4)</div>
214
213
<div class="discord-action-row">
215
- <button class="discord-btn" onclick="copyText('Issue #892 -> PR #142 -> v15.2.0-canary.18', this)">Copy Investigation Summary</button>
214
+ <button class="discord-btn" id="sim-btn-copy-trace">${icons.copy(14, "#ffffff")} Copy Investigation Summary</button>
216
215
</div>
217
216
</div>
218
217
</div>
224
223
return `
225
224
<div class="discord-message">
226
225
<div class="discord-avatar">
227
- <svg viewBox="0 0 16 16"><path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .215-.734.749.749 0 0 1 1.06-.026Zm-6.56 0a.75.75 0 0 1 1.06 0 .749.749 0 0 1 .215.734.749.749 0 0 1-.215.734L2.06 8l3.72 3.72a.749.749 0 0 1-.215.734.749.749 0 0 1-1.06.026L.22 8.53a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0Z"/></svg>
226
+ ${icons.code(22, "#ffffff")}
228
227
</div>
229
228
<div class="discord-content">
230
229
<div class="discord-header">
234
233
</div>
235
234
<div class="command-echo">/code blame file:packages/next/src/server/route-matcher.ts lines:40-46</div>
236
235
<div class="discord-embed" style="border-left-color: #58a6ff">
237
- <div class="embed-author">Code Blame & Attribution</div>
236
+ <div class="embed-author">Code Blame &amp; Attribution</div>
238
237
<div class="embed-title">route-matcher.ts (Lines 40-46)</div>
239
238
<div class="embed-code-block">40 | export function matchRoute(url: string, routes: Route[]): Route | null {
240
239
41 | // [e71ab82 @timneutkens 3d ago] Fast-path lookup for exact match
254
253
return `
255
254
<div class="discord-message">
256
255
<div class="discord-avatar">
257
- <svg viewBox="0 0 16 16"><path d="M1.5 1.75V13.5h13.75a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1-.75-.75V1.75a.75.75 0 0 1 1.5 0Zm14.28 2.53-5.25 5.25a.75.75 0 0 1-1.06 0L7 7.06 2.53 11.53a.75.75 0 0 1-1.06-1.06l5-5a.75.75 0 0 1 1.06 0L10 7.94l4.72-4.72a.75.75 0 0 1 1.06 1.06Z"/></svg>
256
+ ${icons.graph(22, "#ffffff")}
258
257
</div>
259
258
<div class="discord-content">
260
259
<div class="discord-header">
267
266
<div class="embed-author">Developer Engineering Rhythm</div>
268
267
<div class="embed-title">Personal Activity Profile (@swadhin)</div>
269
268
<div class="embed-desc">
270
- Total Commits: <strong>48</strong> β€’ PRs Authored: <strong>6</strong> β€’ PRs Reviewed: <strong>14</strong>
269
+ Total Commits: <strong>48</strong> &bull; PRs Authored: <strong>6</strong> &bull; PRs Reviewed: <strong>14</strong>
271
270
Weekly Rhythm Histogram:
272
271
</div>
273
- <div class="embed-code-block">Mon β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ 14
274
-Tue β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ 10
275
-Wed β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ 6
276
-Thu β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ 12
277
-Fri β–ˆβ–ˆβ–ˆβ–ˆ 4
278
-Sat β–ˆ 1
279
-Sun β–ˆ 1</div>
272
+ <div class="embed-code-block">Mon [||||||||||||||||] 14
273
+Tue [|||||||||||| ] 10
274
+Wed [|||||||| ] 6
275
+Thu [|||||||||||||| ] 12
276
+Fri [|||| ] 4
277
+Sat [| ] 1
278
+Sun [| ] 1</div>
280
279
<div class="embed-grid">
281
280
<div>
282
281
<div class="embed-field-name">Churn Ratio</div>
283
- <div class="embed-field-value">+2,140 / βˆ’840 (2.5x)</div>
282
+ <div class="embed-field-value">+2,140 / &minus;840 (2.5x)</div>
284
283
</div>
285
284
<div>
286
285
<div class="embed-field-name">Average Cycle Time</div>
310
309
const changesBtn = document.getElementById("sim-btn-changes");
311
310
const mergeBtn = document.getElementById("sim-btn-merge");
312
311
const rerunBtn = document.getElementById("sim-btn-rerun");
312
+ const copyTraceBtn = document.getElementById("sim-btn-copy-trace");
313
313
314
314
if (approveBtn) {
315
315
approveBtn.addEventListener("click", () => {
327
327
328
328
if (mergeBtn) {
329
329
mergeBtn.addEventListener("click", () => {
330
- mergeBtn.textContent = "Merging...";
330
+ mergeBtn.innerHTML = `${icons.sync(14, "#ffffff")} Merging...`;
331
331
setTimeout(() => {
332
332
state.prStatus = "merged";
333
333
renderSimulator();
337
337
338
338
if (rerunBtn) {
339
339
rerunBtn.addEventListener("click", () => {
340
- rerunBtn.textContent = "Dispatching GitHub Actions...";
340
+ rerunBtn.innerHTML = `${icons.sync(14, "#ffffff")} Dispatching GitHub Actions...`;
341
341
setTimeout(() => {
342
- rerunBtn.textContent = "Workflows Triggered βœ…";
342
+ rerunBtn.innerHTML = `${icons.check(14, "#3fb950")} Workflows Triggered`;
343
343
}, 700);
344
344
});
345
345
}
346
346
347
+ if (copyTraceBtn) {
348
+ copyTraceBtn.addEventListener("click", () => {
349
+ copyText("Issue #892 -> PR #142 -> v15.2.0-canary.18 (Commit 8f3b12a)", copyTraceBtn);
350
+ });
351
+ }
352
+
347
353
// Repo sub-tabs
348
354
for (const sub of ["overview", "commits", "prs", "issues", "releases"]) {
349
355
const btn = document.getElementById(`sim-repo-${sub}`);
358
364
359
365
// Initialize on DOM load
360
366
document.addEventListener("DOMContentLoaded", () => {
361
- // Tab switching
367
+ // Populate tab button icons dynamically
368
+ const tabIcons: Record<string, string> = {
369
+ pr: icons.gitPullRequest(14),
370
+ repo: icons.repo(14),
371
+ actions: icons.actions(14),
372
+ investigate: icons.investigate(14),
373
+ code: icons.code(14),
374
+ activity: icons.graph(14),
375
+ };
376
+
362
377
const tabs = document.querySelectorAll<HTMLButtonElement>(".sim-tab-btn");
363
378
for (const tab of tabs) {
379
+ const target = tab.getAttribute("data-tab");
380
+ if (target && tabIcons[target]) {
381
+ const label = tab.innerText.replace(/[^a-zA-Z0-9_./#-]/g, "").trim();
382
+ tab.innerHTML = `${tabIcons[target]} <span>/${target === "actions" ? "actions" : target === "activity" ? "activity" : target} ${label}</span>`;
383
+ }
384
+
364
385
tab.addEventListener("click", () => {
365
386
for (const t of tabs) {
366
387
t.classList.remove("active");
367
388
}
368
389
tab.classList.add("active");
369
- const target = tab.getAttribute("data-tab");
370
390
if (target) {
371
391
state.activeTab = target;
372
392
renderSimulator();
373
393
β–Όapps/web/src/icons.ts
+118-0
1
+// Official GitHub Octicons as high-resolution SVGs (Zero Emojis)
2
+
3
+export const icons = {
4
+ gitPullRequest: (size = 16, color = "currentColor") => `
5
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
6
+ <path d="M5 3.254V3.25v.004a.75.75 0 1 1 0-.004Zm1.5 0a2.25 2.25 0 1 0-3 2.122V8.75a2.25 2.25 0 0 0 1.5 2.122v.378a2.25 2.25 0 1 0 1.5 0v-.378a2.25 2.25 0 0 0 1.5-2.122V5.376A2.25 2.25 0 0 0 6.5 3.254ZM2.5 4.75a.75.75 0 1 1 1.5 0 .75.75 0 0 1-1.5 0Zm1.5 6.5a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Zm8-4.75v-.004a.75.75 0 1 0-1.5.004v3.25a2.25 2.25 0 1 0 1.5 2.122V6.5Zm0 5.25a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0ZM12 2.5a2.25 2.25 0 0 0-2.25 2.25v.378a2.25 2.25 0 0 0-1.5 2.122v.004a2.25 2.25 0 0 0 3 2.122V6.5A.75.75 0 0 1 12 5.75h1.25a.75.75 0 0 0 0-1.5H12A2.247 2.247 0 0 0 12 2.5Z"/>
7
+ </svg>
8
+ `,
9
+
10
+ repo: (size = 16, color = "currentColor") => `
11
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
12
+ <path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8ZM5 12.25a.25.25 0 0 1 .25-.25H12v1.5H5.25a.25.25 0 0 1-.25-.25Z"/>
13
+ </svg>
14
+ `,
15
+
16
+ actions: (size = 16, color = "currentColor") => `
17
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
18
+ <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"/>
19
+ </svg>
20
+ `,
21
+
22
+ investigate: (size = 16, color = "currentColor") => `
23
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
24
+ <path d="M8.75.75V3h5.5a.75.75 0 0 1 0 1.5h-5.5v2.25a.75.75 0 0 1-1.5 0V4.5H1.75a.75.75 0 0 1 0-1.5h5.5V.75a.75.75 0 0 1 1.5 0ZM1.75 10h5.5v2.25a.75.75 0 0 0 1.5 0V11.5h5.5a.75.75 0 0 0 0-1.5h-5.5V7.75a.75.75 0 0 0-1.5 0V10H1.75a.75.75 0 0 0 0 1.5Z"/>
25
+ </svg>
26
+ `,
27
+
28
+ code: (size = 16, color = "currentColor") => `
29
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
30
+ <path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .215-.734.749.749 0 0 1 1.06-.026Zm-6.56 0a.75.75 0 0 1 1.06 0 .749.749 0 0 1 .215.734.749.749 0 0 1-.215.734L2.06 8l3.72 3.72a.749.749 0 0 1-.215.734.749.749 0 0 1-1.06.026L.22 8.53a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0Z"/>
31
+ </svg>
32
+ `,
33
+
34
+ graph: (size = 16, color = "currentColor") => `
35
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
36
+ <path d="M1.5 1.75V13.5h13.75a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1-.75-.75V1.75a.75.75 0 0 1 1.5 0Zm14.28 2.53-5.25 5.25a.75.75 0 0 1-1.06 0L7 7.06 2.53 11.53a.75.75 0 0 1-1.06-1.06l5-5a.75.75 0 0 1 1.06 0L10 7.94l4.72-4.72a.75.75 0 0 1 1.06 1.06Z"/>
37
+ </svg>
38
+ `,
39
+
40
+ checkCircle: (size = 16, color = "#3fb950") => `
41
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
42
+ <path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16Zm3.78-9.72a.75.75 0 0 0-1.06-1.06L6.75 9.19 5.28 7.72a.75.75 0 0 0-1.06 1.06l2 2a.75.75 0 0 0 1.06 0l4.5-4.5Z"/>
43
+ </svg>
44
+ `,
45
+
46
+ alertTriangle: (size = 16, color = "#d29922") => `
47
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
48
+ <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"/>
49
+ </svg>
50
+ `,
51
+
52
+ gitMerge: (size = 16, color = "#a371f7") => `
53
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
54
+ <path d="M5 3.254V3.25v.004a.75.75 0 1 1 0-.004Zm1.5 0a2.25 2.25 0 1 0-3 2.122V8.75a2.25 2.25 0 0 0 1.5 2.122v.378a2.25 2.25 0 1 0 1.5 0v-.378a2.25 2.25 0 0 0 1.5-2.122V5.376A2.25 2.25 0 0 0 6.5 3.254Zm5.5 5.496a2.25 2.25 0 1 0-1.5 2.122v.378a2.25 2.25 0 1 0 1.5 0v-.378a2.25 2.25 0 0 0 1.5-2.122v-.004a2.25 2.25 0 0 0-1.5-2.122v.004Zm-2.25 6.5a.75.75 0 1 1 1.5 0 .75.75 0 0 1-1.5 0Zm0-6.5a.75.75 0 1 1 1.5 0 .75.75 0 0 1-1.5 0Zm-4.25-1a.75.75 0 0 1 .75.75v1.25a.75.75 0 0 0 .75.75h1.25a.75.75 0 0 1 0 1.5H8.75A2.25 2.25 0 0 1 6.5 10.5V9.25a.75.75 0 0 1-.75-.75Z"/>
55
+ </svg>
56
+ `,
57
+
58
+ star: (size = 14, color = "#e3b341") => `
59
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
60
+ <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z"/>
61
+ </svg>
62
+ `,
63
+
64
+ repoForked: (size = 14, color = "currentColor") => `
65
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
66
+ <path d="M5 3.25a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Zm0 2.122a2.25 2.25 0 1 0-1.5 0v.878A2.25 2.25 0 0 0 5.75 8.5h4.5A2.25 2.25 0 0 0 12.5 6.25v-.878a2.25 2.25 0 1 0-1.5 0v.878a.75.75 0 0 1-.75.75h-4.5a.75.75 0 0 1-.75-.75v-.878Zm6.75-2.122a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0ZM8 12.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0ZM9.5 12.75a2.25 2.25 0 1 1-3 0V9.25a.75.75 0 0 1 1.5 0v3.5Z"/>
67
+ </svg>
68
+ `,
69
+
70
+ copy: (size = 14, color = "currentColor") => `
71
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
72
+ <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"/>
73
+ <path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"/>
74
+ </svg>
75
+ `,
76
+
77
+ check: (size = 14, color = "#3fb950") => `
78
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
79
+ <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/>
80
+ </svg>
81
+ `,
82
+
83
+ x: (size = 14, color = "#f85149") => `
84
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
85
+ <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"/>
86
+ </svg>
87
+ `,
88
+
89
+ clock: (size = 14, color = "currentColor") => `
90
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
91
+ <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm7-3.25v3.69l2.72 1.63a.75.75 0 1 1-.77 1.28l-3.2-1.92A.75.75 0 0 1 6.5 8.75v-4a.75.75 0 0 1 1.5 0Z"/>
92
+ </svg>
93
+ `,
94
+
95
+ shield: (size = 16, color = "currentColor") => `
96
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
97
+ <path d="M7.467.133a1.748 1.748 0 0 1 1.066 0l5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667l5.25-1.68Z"/>
98
+ </svg>
99
+ `,
100
+
101
+ externalLink: (size = 14, color = "currentColor") => `
102
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
103
+ <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.75-.75a.75.75 0 0 1 .75-.75h3.5c.414 0 .75.336.75.75v3.5a.75.75 0 0 1-1.5 0V3.31L8.53 8.78a.75.75 0 0 1-1.06-1.06l5.47-5.47H11.25a.75.75 0 0 1-.75-.75Z"/>
104
+ </svg>
105
+ `,
106
+
107
+ terminal: (size = 16, color = "currentColor") => `
108
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
109
+ <path d="M0 2.75C0 1.784.784 1 1.75 1h12.5c.966 0 1.75.784 1.75 1.75v10.5A1.75 1.75 0 0 1 14.25 15H1.75A1.75 1.75 0 0 1 0 13.25Zm1.75-.25a.25.25 0 0 0-.25.25v10.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V2.75a.25.25 0 0 0-.25-.25ZM7.28 7.78 4.03 4.53a.75.75 0 0 0-1.06 1.06L5.69 8.31l-2.72 2.72a.75.75 0 1 0 1.06 1.06l3.25-3.25a.75.75 0 0 0 0-1.06Zm1.97 3.47h4a.75.75 0 0 0 0-1.5h-4a.75.75 0 0 0 0 1.5Z"/>
110
+ </svg>
111
+ `,
112
+
113
+ sync: (size = 14, color = "currentColor") => `
114
+ <svg width="${size}" height="${size}" viewBox="0 0 16 16" fill="${color}" style="vertical-align: middle;">
115
+ <path d="M1.705 8.005a.75.75 0 0 1 .834.656 5.5 5.5 0 0 0 9.592 2.97l-1.204-1.204a.25.25 0 0 1 .177-.427h3.646a.25.25 0 0 1 .25.25v3.646a.25.25 0 0 1-.427.177l-1.38-1.38A7.002 7.002 0 0 1 1.05 8.84a.75.75 0 0 1 .655-.835ZM14.295 7.995a.75.75 0 0 1-.834-.656 5.5 5.5 0 0 0-9.592-2.97l1.204 1.204a.25.25 0 0 1-.177.427H1.25a.25.25 0 0 1-.25-.25V2.104a.25.25 0 0 1 .427-.177l1.38 1.38A7.002 7.002 0 0 1 14.95 7.16a.75.75 0 0 1-.655.835Z"/>
116
+ </svg>
117
+ `,
118
+};
0
119
β–Όapps/web/src/index.html
+61-36
4
4
<meta charset="UTF-8" />
5
5
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
<title>DevPulse β€” The GitHub Power-User Operating System for Discord</title>
7
- <meta name="description" content="Stop switching between Discord and your browser. Inspect repositories, review and merge pull requests, trigger CI/CD pipelines, and trace lifecycles right from Discord." />
7
+ <meta name="description" content="Eliminate context switching. Review pull requests, merge code, monitor GitHub Actions CI/CD pipelines, and trace lifecycles directly from Discord." />
8
8
9
9
<!-- OpenGraph / Social Meta Tags -->
10
10
<meta property="og:type" content="website" />
11
- <meta property="og:title" content="DevPulse β€” The GitHub Power-User Operating System for Discord" />
12
- <meta property="og:description" content="Deep GitHub intelligence, pull request reviews, Actions monitoring, and team telemetry inside Discord." />
11
+ <meta property="og:title" content="DevPulse β€” GitHub Power Tools for Discord" />
12
+ <meta property="og:description" content="Deep GitHub intelligence, pull request workflows, CI/CD telemetry, and team velocity inside Discord." />
13
13
<meta property="og:url" content="https://github.com/husteno-o/git-discord-bot" />
14
14
<meta name="twitter:card" content="summary_large_image" />
15
15
<meta name="twitter:title" content="DevPulse β€” GitHub Power Tools in Discord" />
16
- <meta name="twitter:description" content="Never leave Discord for your daily GitHub workflow." />
16
+ <meta name="twitter:description" content="Zero auth for public repositories. AES-256-GCM encrypted PAT vault." />
17
17
18
18
<link rel="stylesheet" href="./styles.css" />
19
19
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%232ea043'><path d='M5 3.254V3.25v.004a.75.75 0 1 1 0-.004Zm1.5 0a2.25 2.25 0 1 0-3 2.122V8.75a2.25 2.25 0 0 0 1.5 2.122v.378a2.25 2.25 0 1 0 1.5 0v-.378a2.25 2.25 0 0 0 1.5-2.122V5.376A2.25 2.25 0 0 0 6.5 3.254Z'/></svg>" />
72
72
</h1>
73
73
74
74
<p class="hero-subtitle">
75
- Eliminate context-switching forever. Review and merge pull requests, inspect repository health, monitor CI/CD Actions runs, trace commit lifecycles, and audit vulnerabilities directly from Discord.
75
+ Eliminate context-switching forever. Review and merge pull requests, inspect repository health, monitor CI/CD Actions pipelines, trace commit lifecycles, and audit vulnerabilities directly from Discord.
76
76
</p>
77
77
78
78
<div class="hero-actions">
84
84
</a>
85
85
86
86
<div class="clone-pill" id="clone-repo-pill" title="Click to copy clone command">
87
- <svg width="14" height="14" viewBox="0 0 16 16">
87
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
88
88
<path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"/>
89
89
<path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"/>
90
90
</svg>
91
91
<span>git clone [email protected]:husteno-o/git-discord-bot.git</span>
92
- <span class="clone-btn-icon">πŸ“‹</span>
92
+ <span class="clone-btn-icon">
93
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
94
+ <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"/>
95
+ <path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"/>
96
+ </svg>
97
+ </span>
93
98
</div>
94
99
</div>
95
100
104
109
</div>
105
110
<div class="hero-badge-item">
106
111
<svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg>
107
- <span>Zero Open Inbound Ports</span>
112
+ <span>Zero Inbound Open Ports</span>
108
113
</div>
109
114
<div class="hero-badge-item">
110
115
<svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg>
130
135
</svg>
131
136
<span>#engineering-ops β€’ DevPulse Interactive Terminal</span>
132
137
</div>
133
- <div style="width: 50px;"></div>
138
+ <div class="simulator-telemetry">
139
+ <span class="telemetry-pill">Latency: &lt;12ms</span>
140
+ </div>
134
141
</div>
135
142
136
143
<div class="simulator-tabs">
137
- <button class="sim-tab-btn active" data-tab="pr">πŸ”€ /pr 142</button>
138
- <button class="sim-tab-btn" data-tab="repo">πŸ“Š /repo vercel/next.js</button>
139
- <button class="sim-tab-btn" data-tab="actions">βš™οΈ /actions main</button>
140
- <button class="sim-tab-btn" data-tab="investigate">πŸ•΅οΈ /investigate #892</button>
141
- <button class="sim-tab-btn" data-tab="code">🧠 /code route-matcher.ts</button>
142
- <button class="sim-tab-btn" data-tab="activity">πŸ“ˆ /activity me</button>
144
+ <button class="sim-tab-btn active" data-tab="pr">
145
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor"><path d="M5 3.254V3.25v.004a.75.75 0 1 1 0-.004Zm1.5 0a2.25 2.25 0 1 0-3 2.122V8.75a2.25 2.25 0 0 0 1.5 2.122v.378a2.25 2.25 0 1 0 1.5 0v-.378a2.25 2.25 0 0 0 1.5-2.122V5.376A2.25 2.25 0 0 0 6.5 3.254Z"/></svg>
146
+ <span>/pr 142</span>
147
+ </button>
148
+ <button class="sim-tab-btn" data-tab="repo">
149
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor"><path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8ZM5 12.25a.25.25 0 0 1 .25-.25H12v1.5H5.25a.25.25 0 0 1-.25-.25Z"/></svg>
150
+ <span>/repo vercel/next.js</span>
151
+ </button>
152
+ <button class="sim-tab-btn" data-tab="actions">
153
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor"><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"/></svg>
154
+ <span>/actions main</span>
155
+ </button>
156
+ <button class="sim-tab-btn" data-tab="investigate">
157
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor"><path d="M8.75.75V3h5.5a.75.75 0 0 1 0 1.5h-5.5v2.25a.75.75 0 0 1-1.5 0V4.5H1.75a.75.75 0 0 1 0-1.5h5.5V.75a.75.75 0 0 1 1.5 0ZM1.75 10h5.5v2.25a.75.75 0 0 0 1.5 0V11.5h5.5a.75.75 0 0 0 0-1.5h-5.5V7.75a.75.75 0 0 0-1.5 0V10H1.75a.75.75 0 0 0 0 1.5Z"/></svg>
158
+ <span>/investigate #892</span>
159
+ </button>
160
+ <button class="sim-tab-btn" data-tab="code">
161
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor"><path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .215-.734.749.749 0 0 1 1.06-.026Zm-6.56 0a.75.75 0 0 1 1.06 0 .749.749 0 0 1 .215.734.749.749 0 0 1-.215.734L2.06 8l3.72 3.72a.749.749 0 0 1-.215.734.749.749 0 0 1-1.06.026L.22 8.53a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0Z"/></svg>
162
+ <span>/code route-matcher.ts</span>
163
+ </button>
164
+ <button class="sim-tab-btn" data-tab="activity">
165
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor"><path d="M1.5 1.75V13.5h13.75a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1-.75-.75V1.75a.75.75 0 0 1 1.5 0Zm14.28 2.53-5.25 5.25a.75.75 0 0 1-1.06 0L7 7.06 2.53 11.53a.75.75 0 0 1-1.06-1.06l5-5a.75.75 0 0 1 1.06 0L10 7.94l4.72-4.72a.75.75 0 0 1 1.06 1.06Z"/></svg>
166
+ <span>/activity me</span>
167
+ </button>
143
168
</div>
144
169
145
170
<div class="simulator-body" id="simulator-render-area">
220
245
</div>
221
246
<span class="feature-command-badge">/code</span>
222
247
</div>
223
- <h3 class="feature-name">Code Viewer & Blame</h3>
248
+ <h3 class="feature-name">Code Viewer &amp; Blame</h3>
224
249
<p class="feature-text">Read remote source code with syntax highlighting, perform git blame on specific line intervals, and resolve which PR introduced a given commit.</p>
225
250
<ul class="feature-bullets">
226
251
<li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> Line-by-line commit authorship</li>
232
257
<div class="feature-card">
233
258
<div class="feature-top">
234
259
<div class="feature-icon-box">
235
- <svg viewBox="0 0 16 16"><path d="M11.5 7a4.499 4.499 0 1 1-8.998 0A4.499 4.499 0 0 1 11.5 7Zm-.82 4.74a6 6 0 1 0-1.06 1.06l3.04 3.04a.75.75 0 1 0 1.06-1.06l-3.04-3.04Z"/></svg>
260
+ <svg viewBox="0 0 16 16"><path d="M8.75.75V3h5.5a.75.75 0 0 1 0 1.5h-5.5v2.25a.75.75 0 0 1-1.5 0V4.5H1.75a.75.75 0 0 1 0-1.5h5.5V.75a.75.75 0 0 1 1.5 0ZM1.75 10h5.5v2.25a.75.75 0 0 0 1.5 0V11.5h5.5a.75.75 0 0 0 0-1.5h-5.5V7.75a.75.75 0 0 0-1.5 0V10H1.75a.75.75 0 0 0 0 1.5Z"/></svg>
236
261
</div>
237
262
<span class="feature-command-badge">/investigate</span>
238
263
</div>
239
264
<h3 class="feature-name">Lifecycle Investigation</h3>
240
- <p class="feature-text">Reconstruct the entire lifecycle of a bug or feature: Originating Issue -> Commits -> Pull Request -> Reviewers -> Merge -> Release Tag.</p>
265
+ <p class="feature-text">Reconstruct the entire lifecycle of a bug or feature: Originating Issue -&gt; Commits -&gt; Pull Request -&gt; Reviewers -&gt; Merge -&gt; Release Tag.</p>
241
266
<ul class="feature-bullets">
242
267
<li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> Complete chronological timeline</li>
243
268
<li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> Identifies approvals and release tags</li>
253
278
<span class="feature-command-badge">/activity</span>
254
279
</div>
255
280
<h3 class="feature-name">Developer Histograms</h3>
256
- <p class="feature-text">Visualize commit rhythms with ASCII weekly bar charts (`Mon β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ`), addition/deletion churn rates, and team turnaround velocity.</p>
281
+ <p class="feature-text">Visualize commit rhythms with ASCII weekly bar charts, addition/deletion churn rates, and team turnaround velocity.</p>
257
282
<ul class="feature-bullets">
258
283
<li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> Terminal-friendly ASCII histograms</li>
259
- <li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> /activity me personal stats</li>
284
+ <li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> /activity me personal statistics</li>
260
285
</ul>
261
286
</div>
262
287
269
294
<span class="feature-command-badge">/trending</span>
270
295
</div>
271
296
<h3 class="feature-name">Ecosystem Radar</h3>
272
- <p class="feature-text">Curated trending repos across modern stacks: TypeScript, Rust, AI/ML, Bun, Databases, Go, and Python with daily and weekly star velocity metrics.</p>
297
+ <p class="feature-text">Curated trending repos across modern stacks: TypeScript, Rust, AI/ML, Bun, Databases, Go, and Python with star velocity metrics.</p>
273
298
<ul class="feature-bullets">
274
299
<li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> 7 modern ecosystem filters</li>
275
300
<li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> High-signal growth filtering</li>
285
310
<span class="feature-command-badge">/watch</span>
286
311
</div>
287
312
<h3 class="feature-name">GitHub Watchtower</h3>
288
- <p class="feature-text">Subscribe specific Discord channels to releases, pull requests, issues, or security advisories. Configure granular event routing per repository.</p>
313
+ <p class="feature-text">Subscribe specific Discord channels to releases, pull requests, issues, or security advisories with granular routing per repo.</p>
289
314
<ul class="feature-bullets">
290
- <li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> Automated webhook delivery</li>
291
- <li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> Multi-channel event distribution</li>
315
+ <li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> Automated event notifications</li>
316
+ <li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> Multi-channel event routing</li>
292
317
</ul>
293
318
</div>
294
319
301
326
<span class="feature-command-badge">/actions</span>
302
327
</div>
303
328
<h3 class="feature-name">CI/CD Workflow Tree</h3>
304
- <p class="feature-text">Visual representation of GitHub Actions pipelines in structured ASCII trees. Track run conclusions, durations, and trigger job reruns directly in Discord.</p>
329
+ <p class="feature-text">Visual representation of GitHub Actions pipelines in structured ASCII trees. Track conclusions, durations, and trigger reruns directly from Discord.</p>
305
330
<ul class="feature-bullets">
306
- <li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> Visual branch & job hierarchy</li>
331
+ <li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> Visual branch &amp; job hierarchy</li>
307
332
<li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> Rerun and cancel workflows</li>
308
333
</ul>
309
334
</div>
316
341
</div>
317
342
<span class="feature-command-badge">/security</span>
318
343
</div>
319
- <h3 class="feature-name">Security & Leak Guard</h3>
344
+ <h3 class="feature-name">Security &amp; Leak Guard</h3>
320
345
<p class="feature-text">Dependabot vulnerability alerts, GHSA / CVE breakdowns, and background message scanner that detects leaked tokens with one-click revocation guides.</p>
321
346
<ul class="feature-bullets">
322
- <li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> Dependabot & GHSA vulnerability feeds</li>
347
+ <li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> Dependabot &amp; GHSA vulnerability feeds</li>
323
348
<li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> Zero-log message secret scanner</li>
324
349
</ul>
325
350
</div>
333
358
<span class="feature-command-badge">/release</span>
334
359
</div>
335
360
<h3 class="feature-name">Release Management</h3>
336
- <p class="feature-text">Inspect published tags, compare commit deltas between releases (`v1.2.0...v1.3.0`), and automatically generate markdown release notes from merged PRs.</p>
361
+ <p class="feature-text">Inspect published tags, compare commit deltas between releases (v1.2.0...v1.3.0), and automatically generate markdown release notes from merged PRs.</p>
337
362
<ul class="feature-bullets">
338
363
<li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> Tag comparison and asset counts</li>
339
364
<li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> Automated changelog generator</li>
348
373
</div>
349
374
<span class="feature-command-badge">/team</span>
350
375
</div>
351
- <h3 class="feature-name">Team Velocity & Balance</h3>
376
+ <h3 class="feature-name">Team Velocity &amp; Balance</h3>
352
377
<p class="feature-text">Team turnaround metrics without toxic vanity rankings. Review velocity, cycle times, and review load balancing to prevent engineering burnout.</p>
353
378
<ul class="feature-bullets">
354
379
<li><svg viewBox="0 0 16 16"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg> Review turnaround cycle times</li>
365
390
<div class="section-header">
366
391
<div class="section-tag">High-Impact Utilities</div>
367
392
<h2 class="section-title">Workflow Accelerators</h2>
368
- <p class="section-desc">Designed to solve everyday engineering bottlenecks in seconds.</p>
393
+ <p class="section-desc">Designed to eliminate engineering bottlenecks in seconds.</p>
369
394
</div>
370
395
371
396
<div class="killer-grid">
382
407
<svg width="18" height="18" viewBox="0 0 16 16" fill="var(--gh-purple)"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.92 6.085h.001a.749.749 0 0 1 1.059-.062 1.488 1.488 0 0 1 .494 1.102c0 .546-.3.923-.627 1.258-.293.301-.597.613-.597 1.117a.75.75 0 0 1-1.5 0c0-.987.585-1.59 1.002-2.018.232-.238.472-.484.472-.757a.253.253 0 0 0-.083-.188.27.27 0 0 0-.174-.052c-.176 0-.31.092-.41.228a.75.75 0 0 1-1.135-.628ZM8 12.5a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"/></svg>
383
408
/why Archaeology
384
409
</h4>
385
- <p class="killer-card-desc">Trace any file and line change back through Commit -> Pull Request -> Originating Issue to answer why a piece of code exists.</p>
410
+ <p class="killer-card-desc">Trace any file and line change back through Commit -&gt; Pull Request -&gt; Originating Issue to answer why a piece of code exists.</p>
386
411
</div>
387
412
388
413
<div class="killer-card">
408
433
<section class="arch-section" id="architecture">
409
434
<div class="container">
410
435
<div class="section-header">
411
- <div class="section-tag">Security & Infrastructure</div>
436
+ <div class="section-tag">Security &amp; Infrastructure</div>
412
437
<h2 class="section-title">Zero-Trust Architecture</h2>
413
438
<p class="section-desc">Engineered for security-conscious teams, open-source communities, and enterprise organizations.</p>
414
439
</div>
452
477
<section class="install-section" id="quickstart">
453
478
<div class="container">
454
479
<div class="section-header">
455
- <div class="section-tag">Self-Hosting & Setup</div>
480
+ <div class="section-tag">Self-Hosting &amp; Setup</div>
456
481
<h2 class="section-title">Get Started in Under 3 Minutes</h2>
457
482
<p class="section-desc">Clone the repository, configure your Discord bot token, and launch DevPulse with Bun.</p>
458
483
</div>
464
489
<span class="window-dot dot-yellow"></span>
465
490
<span class="window-dot dot-green"></span>
466
491
</div>
467
- <span style="font-family: var(--font-mono); font-size: 0.8rem; color: var(--text-secondary);">bash β€’ terminal</span>
492
+ <span style="font-family: var(--font-mono); font-size: 0.8rem; color: var(--text-secondary);">bash &bull; terminal</span>
468
493
<button class="terminal-copy-btn" onclick="copyText('git clone [email protected]:husteno-o/git-discord-bot.git\ncd git-discord-bot\nbun install\ncp .env.example .env\nbun run start', this)" title="Copy all commands">
469
494
<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
470
495
<path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"/>
501
526
Hosting this landing page on Cloudflare Pages:
502
527
</p>
503
528
<div style="display: inline-flex; align-items: center; gap: 8px; padding: 8px 16px; background: var(--bg-surface); border: 1px solid var(--border-default); border-radius: 8px; font-family: var(--font-mono); font-size: 0.85rem; color: var(--gh-blue);">
504
- <span>Deploy Output: <strong>apps/web/dist</strong> β€’ Build Command: <strong>bun run build:web</strong></span>
529
+ <span>Deploy Output: <strong>apps/web/dist</strong> &bull; Build Command: <strong>bun run build:web</strong></span>
505
530
</div>
506
531
</div>
507
532
</div>
508
533
β–Όapps/web/src/styles.css
+20-0
498
498
gap: 8px;
499
499
}
500
500
501
+.simulator-telemetry {
502
+ display: flex;
503
+ align-items: center;
504
+}
505
+
506
+.telemetry-pill {
507
+ font-family: var(--font-mono);
508
+ font-size: 0.72rem;
509
+ color: var(--gh-green-hover);
510
+ background: var(--gh-green-subtle);
511
+ border: 1px solid var(--gh-green-border);
512
+ padding: 2px 8px;
513
+ border-radius: 9999px;
514
+ letter-spacing: 0.3px;
515
+}
516
+
501
517
.simulator-tabs {
502
518
display: flex;
503
519
gap: 4px;
524
540
gap: 8px;
525
541
}
526
542
543
+.sim-tab-btn svg {
544
+ flex-shrink: 0;
545
+}
546
+
527
547
.sim-tab-btn:hover {
528
548
background: var(--bg-surface-hover);
529
549
color: var(--text-primary);
530
550