Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

help.tsx

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

help.tsxBlame593 lines · 1 contributor
80bed05Claude1/**
2 * /help — public quickstart + API cheatsheet for owners migrating their
3 * products onto gluecron. Covers the first five minutes (register, clone,
4 * push), integration surfaces (SSH, import, webhooks, tokens), and the
5 * AI-native extras (gates + AI review). Linked from the landing page nav.
6 *
7 * Uses softAuth so the nav bar renders with the signed-in user's session
8 * cookie when present; the page itself is reachable without auth.
9 */
10
11import { Hono } from "hono";
12import { Layout } from "../views/layout";
13import { softAuth } from "../middleware/auth";
14import type { AuthEnv } from "../middleware/auth";
15
16const help = new Hono<AuthEnv>();
17help.use("*", softAuth);
18
bdb51e4Claude19// ─── PAGE-SCOPED CSS ─────────────────────────────────────────
20// All classes prefixed with `.help-` so styles cannot bleed into other
21// surfaces. Mirrors the 2026 hero polish in admin, dashboard, import,
22// settings, and repo-settings.
23const helpStyles = `
24 .help-wrap { max-width: 920px; margin: 0 auto; padding: var(--space-6) var(--space-4); }
25
26 /* ─── Hero ─── */
27 .help-hero {
28 position: relative;
29 margin-bottom: var(--space-5);
30 padding: var(--space-5) var(--space-6);
31 background: var(--bg-elevated);
32 border: 1px solid var(--border);
33 border-radius: 16px;
34 overflow: hidden;
35 }
36 .help-hero::before {
37 content: '';
38 position: absolute;
39 top: 0; left: 0; right: 0;
40 height: 2px;
41 background: linear-gradient(90deg, transparent 0%, #8c6dff 30%, #36c5d6 70%, transparent 100%);
42 opacity: 0.75;
43 pointer-events: none;
44 }
45 .help-hero-bg {
46 position: absolute;
47 inset: -20% -10% auto auto;
48 width: 360px; height: 360px;
49 pointer-events: none;
50 z-index: 0;
51 }
52 .help-hero-orb {
53 position: absolute;
54 inset: 0;
55 background: radial-gradient(circle, rgba(140,109,255,0.20), rgba(54,197,214,0.10) 45%, transparent 70%);
56 filter: blur(80px);
57 opacity: 0.7;
58 animation: helpHeroOrb 14s ease-in-out infinite;
59 }
60 @keyframes helpHeroOrb {
61 0%, 100% { transform: scale(1) translate(0, 0); opacity: 0.6; }
62 50% { transform: scale(1.1) translate(-10px, 8px); opacity: 0.85; }
63 }
64 @media (prefers-reduced-motion: reduce) {
65 .help-hero-orb { animation: none; }
66 }
67 .help-hero-inner {
68 position: relative;
69 z-index: 1;
70 max-width: 680px;
71 }
72 .help-hero-eyebrow {
73 display: inline-flex;
74 align-items: center;
75 gap: 8px;
76 font-size: 12px;
77 font-weight: 600;
78 letter-spacing: 0.06em;
79 text-transform: uppercase;
80 color: var(--text-muted);
81 margin-bottom: var(--space-3);
82 }
83 .help-hero-eyebrow-pill {
84 display: inline-flex;
85 align-items: center;
86 justify-content: center;
87 width: 22px; height: 22px;
88 border-radius: 7px;
89 background: linear-gradient(135deg, rgba(140,109,255,0.20), rgba(54,197,214,0.18));
90 box-shadow: inset 0 0 0 1px rgba(140,109,255,0.35);
91 color: #c4b6ff;
92 font-size: 13px;
93 line-height: 1;
94 }
95 .help-hero-title {
96 font-size: clamp(28px, 4vw, 40px);
97 font-family: var(--font-display);
98 font-weight: 800;
99 letter-spacing: -0.028em;
100 line-height: 1.05;
101 margin: 0 0 var(--space-3);
102 color: var(--text-strong);
103 }
104 .help-hero-title .help-gradient-text {
105 background-image: linear-gradient(135deg, #a48bff 0%, #8c6dff 50%, #36c5d6 100%);
106 -webkit-background-clip: text;
107 background-clip: text;
108 -webkit-text-fill-color: transparent;
109 color: transparent;
110 }
111 .help-hero-sub {
112 font-size: 15px;
113 color: var(--text-muted);
114 margin: 0;
115 line-height: 1.55;
116 max-width: 600px;
117 }
118
119 /* ─── On-this-page nav ─── */
120 .help-toc {
121 position: relative;
122 padding: var(--space-4) var(--space-5);
123 background: var(--bg-elevated);
124 border: 1px solid var(--border);
125 border-radius: 14px;
126 margin-bottom: var(--space-5);
127 }
128 .help-toc-label {
129 font-size: 11px;
130 font-weight: 600;
131 letter-spacing: 0.08em;
132 text-transform: uppercase;
133 color: var(--accent);
134 margin-bottom: 10px;
135 }
136 .help-toc-list {
137 display: flex;
138 flex-wrap: wrap;
139 gap: 8px;
140 }
141 .help-toc-list a {
142 display: inline-flex;
143 align-items: center;
144 padding: 5px 10px;
145 font-size: 12.5px;
146 color: var(--text);
147 background: var(--bg);
148 border: 1px solid var(--border);
149 border-radius: 8px;
150 text-decoration: none;
151 transition: border-color 120ms ease, background 120ms ease, color 120ms ease;
152 }
153 .help-toc-list a:hover {
154 border-color: rgba(140,109,255,0.45);
155 background: rgba(140,109,255,0.06);
156 color: var(--text-strong);
157 }
158
159 /* ─── Section cards ─── */
160 .help-section {
161 background: var(--bg-elevated);
162 border: 1px solid var(--border);
163 border-radius: 14px;
164 margin-bottom: var(--space-5);
165 overflow: hidden;
166 scroll-margin-top: var(--space-6);
167 }
168 .help-section-head {
169 padding: var(--space-4) var(--space-5) var(--space-3);
170 border-bottom: 1px solid var(--border);
171 }
172 .help-section-eyebrow {
173 font-size: 11px;
174 font-weight: 600;
175 letter-spacing: 0.08em;
176 text-transform: uppercase;
177 color: var(--accent);
178 margin-bottom: 6px;
179 }
180 .help-section-title {
181 font-family: var(--font-display);
182 font-size: 19px;
183 font-weight: 700;
184 letter-spacing: -0.02em;
185 margin: 0 0 4px;
186 color: var(--text-strong);
187 }
188 .help-section-desc {
189 font-size: 13.5px;
190 color: var(--text-muted);
191 margin: 0;
192 line-height: 1.5;
193 }
194 .help-section-body {
195 padding: var(--space-4) var(--space-5);
196 display: flex;
197 flex-direction: column;
198 gap: var(--space-3);
199 }
200
201 /* ─── Item rows inside a section card ─── */
202 .help-item {
203 padding: 12px 14px;
204 background: var(--bg);
205 border: 1px solid var(--border-subtle, var(--border));
206 border-radius: 10px;
207 font-size: 14px;
208 line-height: 1.55;
209 color: var(--text);
210 }
211 .help-item strong { color: var(--text-strong); font-weight: 600; }
212 .help-item code {
213 font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
214 font-size: 12.5px;
215 padding: 1px 5px;
216 border-radius: 4px;
217 background: rgba(140,109,255,0.10);
218 color: #c4b6ff;
219 }
220 .help-item a { color: var(--text-link, var(--accent)); }
221
222 /* ─── Code blocks inside items ─── */
223 .help-code {
224 margin: 8px 0 0;
225 padding: 12px 14px;
226 background: #0a0c14;
227 border: 1px solid var(--border-subtle, var(--border));
228 border-radius: 8px;
229 font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
230 font-size: 12.5px;
231 line-height: 1.55;
232 color: #d6d8e3;
233 overflow-x: auto;
234 }
235
236 /* ─── Footer hint ─── */
237 .help-footnote {
238 margin-top: var(--space-6);
239 padding-top: var(--space-4);
240 border-top: 1px solid var(--border);
241 color: var(--text-muted);
242 font-size: 13px;
243 line-height: 1.55;
244 }
245`;
246
80bed05Claude247help.get("/help", (c) => {
248 const user = c.get("user");
249
250 return c.html(
251 <Layout title="Help — gluecron" user={user}>
bdb51e4Claude252 <style dangerouslySetInnerHTML={{ __html: helpStyles }} />
253 <div class="help-wrap">
254 {/* ─── Hero ─── */}
255 <header class="help-hero">
256 <div class="help-hero-bg" aria-hidden="true">
257 <div class="help-hero-orb" />
258 </div>
259 <div class="help-hero-inner">
260 <div class="help-hero-eyebrow">
261 <span class="help-hero-eyebrow-pill" aria-hidden="true">?</span>
262 <span>Help & quickstart</span>
263 </div>
264 <h1 class="help-hero-title">
265 Ship onto{" "}
266 <span class="help-gradient-text">gluecron</span> in five minutes.
267 </h1>
268 <p class="help-hero-sub">
269 Everything an owner migrating a product onto gluecron needs in one
270 page. If something's unclear, open an issue — link at the bottom.
271 </p>
272 </div>
273 </header>
80bed05Claude274
bdb51e4Claude275 {/* ─── On this page ─── */}
276 <nav class="help-toc" aria-label="On this page">
277 <div class="help-toc-label">On this page</div>
278 <div class="help-toc-list">
279 <a href="#getting-started">Getting started</a>
280 <a href="#git-https">Git over HTTPS</a>
281 <a href="#git-ssh">Git over SSH</a>
282 <a href="#import">Importing from GitHub</a>
283 <a href="#webhooks">Webhooks</a>
284 <a href="#tokens">Personal access tokens</a>
285 <a href="#gates">Gates & AI review</a>
286 <a href="#ai-native">AI-native flow</a>
287 <a href="#shortcuts">Keyboard shortcuts</a>
288 <a href="#api">API</a>
289 </div>
80bed05Claude290 </nav>
291
bdb51e4Claude292 {/* ─── Getting started ─── */}
293 <section id="getting-started" class="help-section">
294 <div class="help-section-head">
295 <div class="help-section-eyebrow">Step 01</div>
296 <h2 class="help-section-title">Getting started</h2>
297 <p class="help-section-desc">
298 Register, verify, and create your first repo.
299 </p>
300 </div>
301 <div class="help-section-body">
302 <div class="help-item">
303 <strong>1. Register an account.</strong>{" "}
304 Head to <a href="/register">/register</a>, pick a username, and
305 set a password. Usernames are your public handle and appear in
306 every repo URL.
80bed05Claude307 </div>
bdb51e4Claude308 <div class="help-item">
309 <strong>2. Verify your email.</strong>{" "}
310 We send a one-time link the first time you sign in. Verified
311 addresses can receive issue, PR, and gate-run notifications.
80bed05Claude312 </div>
bdb51e4Claude313 <div class="help-item">
314 <strong>3. Create your first repo.</strong>{" "}
315 From the dashboard hit <strong>New repository</strong>, or
316 visit <a href="/new">/new</a>. Pick public or private, add a
317 README, and you're ready to clone.
80bed05Claude318 </div>
319 </div>
320 </section>
321
bdb51e4Claude322 {/* ─── Git over HTTPS ─── */}
323 <section id="git-https" class="help-section">
324 <div class="help-section-head">
325 <div class="help-section-eyebrow">Protocol</div>
326 <h2 class="help-section-title">Git over HTTPS</h2>
327 <p class="help-section-desc">
328 HTTPS works out of the box. Authenticate with your account
329 password or, better, a personal access token.
330 </p>
331 </div>
332 <div class="help-section-body">
333 <div class="help-item">
334 <strong>Clone</strong>
335 <pre class="help-code">
80bed05Claude336{`git clone https://<your-host>/<owner>/<repo>.git`}
bdb51e4Claude337 </pre>
80bed05Claude338 </div>
bdb51e4Claude339 <div class="help-item">
340 <strong>Push</strong>
341 <pre class="help-code">
80bed05Claude342{`git push origin main`}
bdb51e4Claude343 </pre>
80bed05Claude344 </div>
bdb51e4Claude345 <div class="help-item">
346 <strong>Pull</strong>
347 <pre class="help-code">
80bed05Claude348{`git pull origin main`}
bdb51e4Claude349 </pre>
80bed05Claude350 </div>
351 </div>
352 </section>
353
bdb51e4Claude354 {/* ─── Git over SSH ─── */}
355 <section id="git-ssh" class="help-section">
356 <div class="help-section-head">
357 <div class="help-section-eyebrow">Protocol</div>
358 <h2 class="help-section-title">Git over SSH</h2>
359 <p class="help-section-desc">
360 SSH avoids typing credentials and is recommended for day-to-day
361 work.
362 </p>
363 </div>
364 <div class="help-section-body">
365 <div class="help-item">
366 <strong>1. Add your key.</strong>{" "}
367 Copy your public key (usually{" "}
368 <code>~/.ssh/id_ed25519.pub</code>) and paste it into{" "}
369 <a href="/settings/keys">/settings/keys</a>. Keys take effect
370 immediately.
80bed05Claude371 </div>
bdb51e4Claude372 <div class="help-item">
373 <strong>2. Clone using the SSH URL.</strong>
374 <pre class="help-code">
80bed05Claude375{`git clone git@<your-host>:<owner>/<repo>.git`}
bdb51e4Claude376 </pre>
80bed05Claude377 </div>
bdb51e4Claude378 <div class="help-item">
379 <strong>3. Rotate or revoke</strong> any key from the same
380 settings page — useful when a laptop walks off.
80bed05Claude381 </div>
382 </div>
383 </section>
384
bdb51e4Claude385 {/* ─── Import ─── */}
386 <section id="import" class="help-section">
387 <div class="help-section-head">
388 <div class="help-section-eyebrow">Migration</div>
389 <h2 class="help-section-title">Importing from GitHub</h2>
390 <p class="help-section-desc">
391 One-time mirror with full history, branches, and tags.
392 </p>
393 </div>
394 <div class="help-section-body">
395 <div class="help-item">
396 Visit <a href="/import">/import</a>, paste the source URL, and
397 gluecron will mirror the repository — full history, branches,
398 and tags. The mirror is a one-time copy; subsequent pushes
399 land on gluecron, not the source. Private sources need a PAT
400 on the source side.
80bed05Claude401 </div>
402 </div>
403 </section>
404
bdb51e4Claude405 {/* ─── Webhooks ─── */}
406 <section id="webhooks" class="help-section">
407 <div class="help-section-head">
408 <div class="help-section-eyebrow">Integrations</div>
409 <h2 class="help-section-title">Webhooks</h2>
410 <p class="help-section-desc">
411 Per-repo webhooks live at{" "}
412 <code>/:owner/:repo/settings/webhooks</code>. Register a URL, pick
413 events (push, issue, pr, star), and set a secret.
414 </p>
415 </div>
416 <div class="help-section-body">
417 <div class="help-item">
418 <strong>HMAC signature.</strong>{" "}
419 Every delivery includes{" "}
420 <code>X-Gluecron-Signature: sha256=&lt;hex&gt;</code>.{" "}
421 Compute HMAC-SHA256 over the raw request body using your
422 secret and compare in constant time.
80bed05Claude423 </div>
bdb51e4Claude424 <div class="help-item">
425 <strong>Payload shape.</strong>
426 <pre class="help-code">
80bed05Claude427{`{
428 "event": "push",
429 "repo": { "owner": "acme", "name": "api" },
430 "ref": "refs/heads/main",
431 "before": "<sha>",
432 "after": "<sha>",
433 "commits": [ /* ... */ ],
434 "sender": { "username": "kit" }
435}`}
bdb51e4Claude436 </pre>
80bed05Claude437 </div>
bdb51e4Claude438 <div class="help-item">
439 Deliveries are retried with exponential backoff; inspect the
440 last N attempts from the webhook's settings page.
80bed05Claude441 </div>
442 </div>
443 </section>
444
bdb51e4Claude445 {/* ─── Tokens ─── */}
446 <section id="tokens" class="help-section">
447 <div class="help-section-head">
448 <div class="help-section-eyebrow">Auth</div>
449 <h2 class="help-section-title">Personal access tokens</h2>
450 <p class="help-section-desc">
451 Tokens authenticate CLI clients, CI jobs, and scripts. Create
452 them at <a href="/settings/tokens">/settings/tokens</a>; the value
453 is shown once, so copy it immediately. Tokens start with{" "}
454 <code>glc_</code>.
455 </p>
456 </div>
457 <div class="help-section-body">
458 <div class="help-item">
459 <strong>Example: list your repos via the API.</strong>
460 <pre class="help-code">
80bed05Claude461{`curl -H "Authorization: Bearer glc_your_token_here" \\
462 https://<your-host>/api/v2/repos`}
bdb51e4Claude463 </pre>
80bed05Claude464 </div>
bdb51e4Claude465 <div class="help-item">
466 Tokens can also authenticate <code>git</code> over HTTPS — use
467 the token as the password in place of your account password.
80bed05Claude468 </div>
469 </div>
470 </section>
471
bdb51e4Claude472 {/* ─── Gates & AI review ─── */}
473 <section id="gates" class="help-section">
474 <div class="help-section-head">
475 <div class="help-section-eyebrow">Quality</div>
476 <h2 class="help-section-title">Gates & AI review</h2>
477 <p class="help-section-desc">
478 Push-time scanning + an AI pair reviewer on every PR.
479 </p>
480 </div>
481 <div class="help-section-body">
482 <div class="help-item">
483 Every push to the default branch (usually <code>main</code>)
484 triggers a gate run: GateTest scans the diff for secrets,
485 dependency advisories, and policy violations, while the AI
486 reviewer reads the patch and comments on any PRs that touch
487 the same files. Failing gates block the push by default;
488 results appear on the commit page and in the repo's{" "}
489 <em>Gate runs</em> tab. Configure gate policy per-repo in
490 <strong> Settings → Gates</strong>.
80bed05Claude491 </div>
492 </div>
493 </section>
494
bdb51e4Claude495 {/* ─── AI-native flow ─── */}
496 <section id="ai-native" class="help-section">
497 <div class="help-section-head">
498 <div class="help-section-eyebrow">AI-native</div>
499 <h2 class="help-section-title">AI-native flow</h2>
500 <p class="help-section-desc">
501 Surfaces that ride on <code>ANTHROPIC_API_KEY</code>, with
502 deterministic fallbacks when it's missing.
503 </p>
504 </div>
505 <div class="help-section-body">
506 <div class="help-item">
507 <strong>Issue → PR in one click.</strong> Open any issue you
508 own and hit <em>Build with AI</em> in the header. The spec
509 form pre-fills with the issue title + body and a{" "}
510 <code>Closes #N</code> footer; Claude drafts the diff, opens
511 a draft PR, and the merge auto-closes the originating issue.
2afb411Claude512 </div>
bdb51e4Claude513 <div class="help-item">
514 <strong>AI-drafted PR descriptions.</strong> The new-PR form
515 has a <em>Suggest description with AI</em> button that runs
516 <code> generatePrSummary</code> against{" "}
517 <code>git diff base...head</code> and fills the description
518 with a structured summary (Why · Key changes · Test plan ·
519 Risks).
2afb411Claude520 </div>
bdb51e4Claude521 <div class="help-item">
522 <strong>Auto-review on PR open.</strong> Non-draft PRs get a
523 summary comment plus inline file/line annotations from the
524 AI reviewer. A second comment posts label + reviewer +
525 priority suggestions (the <em>AI Triage</em> block). All
526 suggestions; nothing applied automatically.
2afb411Claude527 </div>
bdb51e4Claude528 <div class="help-item">
529 <strong>Repo-wide AI surfaces.</strong>{" "}
530 <a href="/help#explore">Explain</a> a codebase, run{" "}
531 <a href="/help#explore">semantic search</a>, ask the chat
532 anything about the repo, generate failing test stubs from a
533 source file (the <em>Tests</em> link in the repo nav), and
534 draft full PRs from a plain-English spec via{" "}
535 <em>Spec to PR</em>. All require{" "}
536 <code>ANTHROPIC_API_KEY</code>; without it the surfaces
537 degrade gracefully to deterministic fallbacks.
2afb411Claude538 </div>
bdb51e4Claude539 <div class="help-item">
540 <strong>Scheduled workflows.</strong> Drop{" "}
541 <code>on: schedule: [{`{cron: "0 * * * *"}`}]</code> into any
542 <code> .gluecron/workflows/*.yml</code>. The autopilot
543 ticker fires the cron from the same node that handles your
544 pushes — no external scheduler needed.
2afb411Claude545 </div>
546 </div>
547 </section>
548
bdb51e4Claude549 {/* ─── Shortcuts ─── */}
550 <section id="shortcuts" class="help-section">
551 <div class="help-section-head">
552 <div class="help-section-eyebrow">Power user</div>
553 <h2 class="help-section-title">Keyboard shortcuts</h2>
554 <p class="help-section-desc">
555 Press <code>?</code> on any page to pop the overlay.
556 </p>
557 </div>
558 <div class="help-section-body">
559 <div class="help-item">
560 gluecron ships a full keyboard-first mode — see{" "}
561 <a href="/shortcuts">/shortcuts</a> for the complete cheat
562 sheet. Press <code>?</code> on any page to pop the overlay.
80bed05Claude563 </div>
564 </div>
565 </section>
566
bdb51e4Claude567 {/* ─── API ─── */}
568 <section id="api" class="help-section">
569 <div class="help-section-head">
570 <div class="help-section-eyebrow">Reference</div>
571 <h2 class="help-section-title">API</h2>
572 <p class="help-section-desc">
573 REST + GraphQL surfaces, both documented inline.
574 </p>
575 </div>
576 <div class="help-section-body">
577 <div class="help-item">
578 Full REST + GraphQL reference lives at{" "}
579 <a href="/api/docs">/api/docs</a>. The GraphQL explorer is at{" "}
580 <a href="/api/graphql">/api/graphql</a>.
80bed05Claude581 </div>
582 </div>
583 </section>
584
bdb51e4Claude585 <p class="help-footnote">
80bed05Claude586 Something missing? Open an issue on gluecron's source repo.
587 </p>
588 </div>
589 </Layout>
590 );
591});
592
593export default help;