create-githat-app 1.6.0 β†’ 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/cli.js +5 -5
  2. package/package.json +6 -2
  3. package/templates/agent/app/(auth)/forgot-password/page.tsx.hbs +11 -0
  4. package/templates/agent/app/(auth)/reset-password/page.tsx.hbs +39 -0
  5. package/templates/agent/app/(auth)/verify-email/page.tsx.hbs +41 -0
  6. package/templates/agent/app/admin/agent/page.tsx.hbs +159 -62
  7. package/templates/agent/app/admin/layout.tsx.hbs +82 -0
  8. package/templates/agent/app/admin/mcp/page.tsx.hbs +156 -0
  9. package/templates/agent/app/dashboard/agents/page.tsx.hbs +9 -0
  10. package/templates/agent/app/dashboard/layout.tsx.hbs +9 -0
  11. package/templates/agent/app/dashboard/mcp/page.tsx.hbs +9 -0
  12. package/templates/agent/app/dashboard/page.tsx.hbs +128 -0
  13. package/templates/agent/app/globals.css.hbs +14 -9
  14. package/templates/agent/app/layout.tsx.hbs +7 -1
  15. package/templates/agent/app/page.tsx.hbs +127 -70
  16. package/templates/agent/app/verify/agent/page.tsx.hbs +124 -0
  17. package/templates/agent/next.config.ts.hbs +4 -5
  18. package/templates/agent/public/HERO_IMAGE.md +23 -0
  19. package/templates/base/githat/api/agents.ts.hbs +6 -6
  20. package/templates/base/githat/config.ts.hbs +7 -2
  21. package/templates/base/githat/dashboard/overview.tsx.hbs +106 -16
  22. package/templates/classroom/app/layout.tsx.hbs +6 -0
  23. package/templates/classroom/next.config.ts.hbs +4 -5
  24. package/templates/content/app/layout.tsx.hbs +6 -0
  25. package/templates/content/next.config.ts.hbs +4 -5
  26. package/templates/dashboard/app/admin/data/[entity]/page.tsx.hbs +2 -2
  27. package/templates/dashboard/app/layout.tsx.hbs +6 -0
  28. package/templates/dashboard/next.config.ts.hbs +4 -5
  29. package/templates/fullstack/apps-web-nextjs/app/layout.tsx.hbs +6 -0
  30. package/templates/fullstack/apps-web-nextjs/next.config.ts.hbs +5 -5
  31. package/templates/marketplace/app/layout.tsx.hbs +6 -0
  32. package/templates/marketplace/next.config.ts.hbs +4 -5
  33. package/templates/nextjs/app/(auth)/forgot-password/page.tsx.hbs +2 -54
  34. package/templates/nextjs/app/(auth)/reset-password/page.tsx.hbs +8 -75
  35. package/templates/nextjs/app/layout.tsx.hbs +6 -0
  36. package/templates/nextjs/next.config.ts.hbs +4 -5
  37. package/templates/plain/app/layout.tsx.hbs +6 -0
  38. package/templates/plain/next.config.ts.hbs +4 -5
  39. package/templates/portfolio/app/layout.tsx.hbs +6 -0
  40. package/templates/portfolio/next.config.ts.hbs +4 -5
  41. package/templates/saas/app/layout.tsx.hbs +6 -0
  42. package/templates/saas/next.config.ts.hbs +4 -5
  43. package/templates/agent/proxy.ts.hbs +0 -10
  44. package/templates/classroom/proxy.ts.hbs +0 -10
  45. package/templates/content/proxy.ts.hbs +0 -10
  46. package/templates/dashboard/proxy.ts.hbs +0 -10
  47. package/templates/marketplace/app/(shop)/[slug]/p/[productId]/page.tsx.hbs +0 -99
  48. package/templates/marketplace/app/(shop)/[slug]/page.tsx.hbs +0 -90
  49. package/templates/marketplace/proxy.ts.hbs +0 -10
  50. package/templates/nextjs/proxy.ts.hbs +0 -10
  51. package/templates/plain/proxy.ts.hbs +0 -10
  52. package/templates/portfolio/proxy.ts.hbs +0 -10
  53. package/templates/saas/proxy.ts.hbs +0 -10
@@ -0,0 +1,156 @@
1
+ 'use client';
2
+
3
+ import { useAuth } from '@githat/nextjs';
4
+
5
+ const DEMO_SERVERS = [
6
+ {
7
+ name: 'web-search',
8
+ description: 'Search the web and fetch pages',
9
+ tools: ['web.search', 'web.fetch'],
10
+ status: 'connected' as const,
11
+ },
12
+ {
13
+ name: 'arxiv',
14
+ description: 'Read and search arXiv papers',
15
+ tools: ['arxiv.read', 'arxiv.search'],
16
+ status: 'connected' as const,
17
+ },
18
+ {
19
+ name: 'github',
20
+ description: 'Read and write GitHub repos',
21
+ tools: ['github.read', 'github.push'],
22
+ status: 'disconnected' as const,
23
+ },
24
+ ];
25
+
26
+ export default function McpAdminPage() {
27
+ const { isSignedIn, isLoading } = useAuth();
28
+
29
+ if (isLoading) return <div style=\{{ padding: 'var(--space-8)', color: 'var(--fg-muted)' }}>Loading…</div>;
30
+ if (!isSignedIn) return null;
31
+
32
+ return (
33
+ <div style=\{{ padding: 'var(--space-8) var(--space-6)', maxWidth: '52rem' }}>
34
+ <div style=\{{ marginBottom: 'var(--space-6)' }}>
35
+ <h1 style=\{{ fontSize: '1.5rem', fontWeight: 700, marginBottom: 'var(--space-2)' }}>MCP Servers</h1>
36
+ <p style=\{{ fontSize: '0.875rem', color: 'var(--fg-muted)' }}>
37
+ Model Context Protocol servers expose tools your agent can call. Connect servers
38
+ to grant your agent access to the tools they expose.
39
+ </p>
40
+ </div>
41
+
42
+ <div style=\{{ display: 'flex', flexDirection: 'column', gap: 'var(--space-4)' }}>
43
+ {DEMO_SERVERS.map((server) => (
44
+ <div
45
+ key={server.name}
46
+ style=\{{
47
+ padding: 'var(--space-5)',
48
+ borderRadius: 'var(--radius-lg)',
49
+ border: '1px solid var(--border)',
50
+ background: 'var(--surface)',
51
+ display: 'flex',
52
+ alignItems: 'flex-start',
53
+ justifyContent: 'space-between',
54
+ gap: 'var(--space-4)',
55
+ }}
56
+ >
57
+ <div style=\{{ flex: 1 }}>
58
+ <div style=\{{ display: 'flex', alignItems: 'center', gap: 'var(--space-3)', marginBottom: 'var(--space-2)' }}>
59
+ <code style=\{{ fontFamily: 'var(--font-mono)', fontSize: '0.9375rem', fontWeight: 600 }}>
60
+ {server.name}
61
+ </code>
62
+ <span style=\{{
63
+ padding: '0.125rem var(--space-2)',
64
+ borderRadius: 'var(--radius-full)',
65
+ fontSize: '0.6875rem',
66
+ fontWeight: 700,
67
+ textTransform: 'uppercase',
68
+ letterSpacing: '0.04em',
69
+ background: server.status === 'connected' ? 'var(--success)' : 'var(--border)',
70
+ color: server.status === 'connected' ? '#fff' : 'var(--fg-muted)',
71
+ }}>
72
+ {server.status}
73
+ </span>
74
+ </div>
75
+ <p style=\{{ fontSize: '0.875rem', color: 'var(--fg-muted)', marginBottom: 'var(--space-3)' }}>
76
+ {server.description}
77
+ </p>
78
+ <div style=\{{ display: 'flex', flexWrap: 'wrap', gap: 'var(--space-2)' }}>
79
+ {server.tools.map((tool) => (
80
+ <span
81
+ key={tool}
82
+ style=\{{
83
+ padding: 'var(--space-1) var(--space-2)',
84
+ borderRadius: 'var(--radius-md)',
85
+ border: '1px solid var(--border)',
86
+ fontSize: '0.75rem',
87
+ fontFamily: 'var(--font-mono)',
88
+ color: 'var(--fg-muted)',
89
+ }}
90
+ >
91
+ {tool}
92
+ </span>
93
+ ))}
94
+ </div>
95
+ </div>
96
+ <button
97
+ style=\{{
98
+ flexShrink: 0,
99
+ padding: 'var(--space-2) var(--space-4)',
100
+ borderRadius: 'var(--radius-md)',
101
+ border: '1px solid var(--border)',
102
+ background: 'transparent',
103
+ color: server.status === 'connected' ? 'var(--danger)' : 'var(--primary)',
104
+ fontSize: '0.875rem',
105
+ fontWeight: 600,
106
+ cursor: 'pointer',
107
+ }}
108
+ >
109
+ {server.status === 'connected' ? 'Disconnect' : 'Connect'}
110
+ </button>
111
+ </div>
112
+ ))}
113
+ </div>
114
+
115
+ <div style=\{{
116
+ marginTop: 'var(--space-8)',
117
+ padding: 'var(--space-5)',
118
+ borderRadius: 'var(--radius-lg)',
119
+ border: '1px dashed var(--border)',
120
+ textAlign: 'center',
121
+ }}>
122
+ <p style=\{{ fontSize: '0.875rem', color: 'var(--fg-muted)', marginBottom: 'var(--space-3)' }}>
123
+ Connect a custom MCP server by URL
124
+ </p>
125
+ <div style=\{{ display: 'flex', gap: 'var(--space-2)', maxWidth: '28rem', margin: '0 auto' }}>
126
+ <input
127
+ type="url"
128
+ placeholder="https://my-mcp-server.com/sse"
129
+ style=\{{
130
+ flex: 1,
131
+ padding: 'var(--space-2) var(--space-3)',
132
+ borderRadius: 'var(--radius-md)',
133
+ border: '1px solid var(--border)',
134
+ background: 'var(--bg)',
135
+ color: 'var(--fg)',
136
+ fontSize: '0.875rem',
137
+ fontFamily: 'var(--font-mono)',
138
+ }}
139
+ />
140
+ <button style=\{{
141
+ padding: 'var(--space-2) var(--space-4)',
142
+ borderRadius: 'var(--radius-md)',
143
+ border: 'none',
144
+ background: 'var(--primary)',
145
+ color: '#fff',
146
+ fontSize: '0.875rem',
147
+ fontWeight: 600,
148
+ cursor: 'pointer',
149
+ }}>
150
+ Add
151
+ </button>
152
+ </div>
153
+ </div>
154
+ </div>
155
+ );
156
+ }
@@ -0,0 +1,9 @@
1
+ {{#if includeAgentModule}}
2
+ {{#if includeGithatFolder}}
3
+ import { DashboardAgents } from '../../../githat/dashboard/agents{{#unless typescript}}.jsx{{/unless}}';
4
+
5
+ export default function AgentsPage() {
6
+ return <DashboardAgents />;
7
+ }
8
+ {{/if}}
9
+ {{/if}}
@@ -0,0 +1,9 @@
1
+ {{#if includeDashboard}}
2
+ {{#if includeGithatFolder}}
3
+ import { DashboardLayout } from '../../githat/dashboard/layout{{#unless typescript}}.jsx{{/unless}}';
4
+
5
+ export default function Layout({ children }{{#if typescript}}: { children: React.ReactNode }{{/if}}) {
6
+ return <DashboardLayout>{children}</DashboardLayout>;
7
+ }
8
+ {{/if}}
9
+ {{/if}}
@@ -0,0 +1,9 @@
1
+ {{#if includeMcpModule}}
2
+ {{#if includeGithatFolder}}
3
+ import { DashboardMcpServers } from '../../../githat/dashboard/mcp-servers{{#unless typescript}}.jsx{{/unless}}';
4
+
5
+ export default function McpPage() {
6
+ return <DashboardMcpServers />;
7
+ }
8
+ {{/if}}
9
+ {{/if}}
@@ -0,0 +1,128 @@
1
+ {{#if includeDashboard}}
2
+ 'use client';
3
+
4
+ import { useEffect, useState } from 'react';
5
+ import Link from 'next/link';
6
+ import { useAuth } from '@githat/nextjs';
7
+ import { githatApi } from '../../../githat/api/client{{#unless typescript}}.js{{/unless}}';
8
+ {{#if typescript}}
9
+ interface AgentSummary {
10
+ total: number;
11
+ active: number;
12
+ actionsLast24h: number;
13
+ mcpServers: number;
14
+ }
15
+ {{/if}}
16
+
17
+ export default function DashboardPage() {
18
+ const { user, org } = useAuth();
19
+ const [summary, setSummary] = useState{{#if typescript}}<AgentSummary>{{/if}}({
20
+ total: 0,
21
+ active: 0,
22
+ actionsLast24h: 0,
23
+ mcpServers: 0,
24
+ });
25
+
26
+ useEffect(() => {
27
+ githatApi.get{{#if typescript}}<AgentSummary>{{/if}}('/agents/summary')
28
+ .then((data) => setSummary(data))
29
+ .catch(() => {});
30
+ }, []);
31
+
32
+ return (
33
+ <div>
34
+ <div style=\{{ marginBottom: '2rem' }}>
35
+ <h1 style=\{{ fontSize: '1.5rem', fontWeight: 700, color: '#fafafa', marginBottom: '0.375rem' }}>
36
+ Welcome back{user?.name ? `, ${user.name}` : ''}
37
+ </h1>
38
+ {org && (
39
+ <p style=\{{ color: '#71717a', fontSize: '0.875rem' }}>
40
+ {org.name} Β· <span style=\{{ color: '#a1a1aa' }}>{org.role}</span>
41
+ </p>
42
+ )}
43
+ </div>
44
+
45
+ {/* Stats row */}
46
+ <div style=\{{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(14rem, 1fr))', gap: '1rem', marginBottom: '2.5rem' }}>
47
+ {[
48
+ { label: 'Total agents', value: summary.total, sub: 'Registered' },
49
+ { label: 'Active agents', value: summary.active, sub: 'Running now' },
50
+ { label: 'Actions (24h)', value: summary.actionsLast24h, sub: 'Across all agents' },
51
+ { label: 'MCP servers', value: summary.mcpServers, sub: `Plan: ${org?.tier ?? 'Free'}` },
52
+ ].map(({ label, value, sub }) => (
53
+ <div key={label} style=\{{
54
+ background: '#111113',
55
+ border: '1px solid #1e1e2e',
56
+ borderRadius: '0.75rem',
57
+ padding: '1.5rem',
58
+ }}>
59
+ <p style=\{{ fontSize: '0.8125rem', color: '#71717a', marginBottom: '0.375rem' }}>{label}</p>
60
+ <p style=\{{ fontSize: '1.5rem', fontWeight: 700, color: '#fafafa', marginBottom: '0.25rem' }}>{value}</p>
61
+ <p style=\{{ fontSize: '0.75rem', color: '#52525b' }}>{sub}</p>
62
+ </div>
63
+ ))}
64
+ </div>
65
+
66
+ {/* Quick actions */}
67
+ <div style=\{{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(20rem, 1fr))', gap: '1rem' }}>
68
+ {[
69
+ {
70
+ title: 'Register an AI agent',
71
+ desc: 'Assign a wallet-bound identity to a new autonomous agent. Capability-scoped, kill-switchable, fully audited.',
72
+ cta: 'Register agent',
73
+ href: '/dashboard/agents',
74
+ accent: '#6366f1',
75
+ },
76
+ {
77
+ title: 'Connect an MCP server',
78
+ desc: 'Grant your agents access to new tools by connecting a Model Context Protocol server.',
79
+ cta: 'Connect server',
80
+ href: '/dashboard/mcp',
81
+ accent: '#0ea5e9',
82
+ },
83
+ {
84
+ title: 'Invite team members',
85
+ desc: 'Add collaborators who can monitor agents, adjust capabilities, or trigger the kill switch.',
86
+ cta: 'Invite',
87
+ href: '/dashboard/members',
88
+ accent: '#10b981',
89
+ },
90
+ {
91
+ title: 'Agent operator console',
92
+ desc: 'View live status, adjust capabilities, and hit the kill switch for a specific agent.',
93
+ cta: 'Open console',
94
+ href: '/admin/agent',
95
+ accent: '#f59e0b',
96
+ },
97
+ ].map(({ title, desc, cta, href, accent }) => (
98
+ <div key={title} style=\{{
99
+ background: '#111113',
100
+ border: '1px solid #1e1e2e',
101
+ borderRadius: '0.75rem',
102
+ padding: '1.5rem',
103
+ display: 'flex',
104
+ flexDirection: 'column',
105
+ gap: '0.75rem',
106
+ }}>
107
+ <h3 style=\{{ fontSize: '0.9375rem', fontWeight: 600, color: '#fafafa' }}>{title}</h3>
108
+ <p style=\{{ fontSize: '0.875rem', color: '#71717a', lineHeight: 1.6, flex: 1 }}>{desc}</p>
109
+ <Link href={href} style=\{{
110
+ display: 'inline-block',
111
+ background: accent,
112
+ color: '#fff',
113
+ textDecoration: 'none',
114
+ padding: '0.5rem 1rem',
115
+ borderRadius: '0.375rem',
116
+ fontSize: '0.875rem',
117
+ fontWeight: 600,
118
+ alignSelf: 'flex-start',
119
+ }}>
120
+ {cta} β†’
121
+ </Link>
122
+ </div>
123
+ ))}
124
+ </div>
125
+ </div>
126
+ );
127
+ }
128
+ {{/if}}
@@ -39,21 +39,26 @@
39
39
  --danger: #dc2626;
40
40
 
41
41
  /* Spacing β€” used by @githat/nextjs/styles */
42
- --space-1: 0.25rem;
43
- --space-2: 0.5rem;
44
- --space-3: 0.75rem;
45
- --space-4: 1rem;
46
- --space-6: 1.5rem;
47
- --space-8: 2rem;
42
+ --space-1: 0.25rem;
43
+ --space-2: 0.5rem;
44
+ --space-3: 0.75rem;
45
+ --space-4: 1rem;
46
+ --space-5: 1.25rem;
47
+ --space-6: 1.5rem;
48
+ --space-8: 2rem;
49
+ --space-10: 2.5rem;
50
+ --space-12: 3rem;
48
51
 
49
52
  /* Radius */
50
- --radius: 0.5rem;
51
- --radius-md: 0.5rem;
52
- --radius-lg: 0.75rem;
53
+ --radius: 0.5rem;
54
+ --radius-md: 0.5rem;
55
+ --radius-lg: 0.75rem;
56
+ --radius-full: 9999px;
53
57
 
54
58
  /* Fonts */
55
59
  --font-sans: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
56
60
  --font-wordmark: 'Instrument Serif', Georgia, serif;
61
+ --font-mono: 'JetBrains Mono', 'Fira Code', ui-monospace, monospace;
57
62
  }
58
63
 
59
64
  @media (prefers-color-scheme: dark) {
@@ -19,9 +19,15 @@ export default function RootLayout({ children }{{#if typescript}}: { children: R
19
19
  */}
20
20
  <GitHatProvider config=\{{
21
21
  publishableKey: process.env.NEXT_PUBLIC_GITHAT_PUBLISHABLE_KEY || '',
22
+ apiUrl: 'https://api.githat.io',
23
+ {{#if typescript}}
24
+ tokenStorage: 'localStorage' as const,
25
+ {{else}}
26
+ tokenStorage: 'localStorage',
27
+ {{/if}}
22
28
  signInUrl: '/sign-in',
23
29
  signUpUrl: '/sign-up',
24
- afterSignInUrl: '/',
30
+ afterSignInUrl: '/dashboard',
25
31
  afterSignOutUrl: '/',
26
32
  }}>
27
33
  <header style=\{{
@@ -4,90 +4,52 @@ import Link from 'next/link';
4
4
  import { useAuth } from '@githat/nextjs';
5
5
 
6
6
  /**
7
- * AI Agent template β€” Web4 identity, MCP, public verification.
7
+ * Landing page β€” split-hero layout.
8
8
  *
9
- * The pitch: every other auth platform stops at humans. GitHat
10
- * extends identity to autonomous agents β€” wallet-bound (Ethereum
11
- * sigs), capability-scoped, kill-switchable, audit-logged. Anyone
12
- * can verify an agent at /verify/agent/<wallet>.
9
+ * Left: pitch + CTA
10
+ * Right: your hero image or logo (drop a file in public/ and swap
11
+ * <HeroImagePlaceholder /> for <Image src="/your-image.png" ... />).
13
12
  *
14
- * This template is the agent operator's dashboard, plus the public
15
- * /verify endpoint anyone can hit to check an agent's status.
13
+ * The <Image> tag from next/image is already imported so the swap is
14
+ * one line. See public/HERO_IMAGE.md for full instructions.
16
15
  */
17
- export default function Home() {
18
- const { isSignedIn } = useAuth();
19
16
 
17
+ function HeroImagePlaceholder() {
20
18
  return (
21
- <div style=\{{ background: 'var(--bg)', color: 'var(--fg)', minHeight: 'calc(100vh - 64px)' }}>
22
- <section style=\{{
23
- padding: 'var(--space-12) var(--space-4)',
24
- textAlign: 'center',
25
- maxWidth: '40rem',
26
- margin: '0 auto',
27
- }}>
28
- <h1 style=\{{
29
- fontFamily: 'var(--font-wordmark, Georgia, serif)',
30
- fontSize: 'clamp(2rem, 5vw, 3rem)',
31
- lineHeight: 1.1,
32
- marginBottom: 'var(--space-3)',
33
- }}>
34
- {{businessName}}
35
- </h1>
36
- <p style=\{{ color: 'var(--fg-muted)', fontSize: '1.125rem', marginBottom: 'var(--space-6)' }}>
37
- Wallet-bound identity for autonomous AI agents. Capability
38
- scoping, kill switch, audit trail β€” and a public /verify
39
- endpoint anyone can hit.
40
- </p>
41
- {!isSignedIn ? (
42
- <Link href="/sign-up" style=\{{
43
- display: 'inline-block',
44
- padding: 'var(--space-3) var(--space-6)',
45
- borderRadius: 'var(--radius-md, 0.5rem)',
46
- background: 'var(--primary)',
47
- color: 'var(--bg)',
48
- fontWeight: 600,
49
- textDecoration: 'none',
50
- }}>
51
- Register an agent β†’
52
- </Link>
53
- ) : (
54
- <Link href="/admin/agent" style=\{{
55
- display: 'inline-block',
56
- padding: 'var(--space-3) var(--space-6)',
57
- borderRadius: 'var(--radius-md, 0.5rem)',
58
- background: 'var(--primary)',
59
- color: 'var(--bg)',
60
- fontWeight: 600,
61
- textDecoration: 'none',
62
- }}>
63
- Open agent dashboard β†’
64
- </Link>
65
- )}
66
- </section>
67
-
68
- <section style=\{{ padding: 'var(--space-8) var(--space-4)', background: 'var(--surface-sub)' }}>
69
- <div style=\{{ maxWidth: '48rem', margin: '0 auto' }}>
70
- <h2 style=\{{ fontSize: '1.5rem', marginBottom: 'var(--space-4)' }}>What you get</h2>
71
- <ul style=\{{ listStyle: 'none', padding: 0, margin: 0, display: 'flex', flexDirection: 'column', gap: 'var(--space-3)' }}>
72
- <Item emoji="πŸͺͺ" title="Wallet-bound identity" body="Ethereum-style key pair. The agent signs requests; clients verify the signature. No shared secrets to leak." />
73
- <Item emoji="🎚" title="Capability scopes" body="Each agent can only call the tools you explicitly granted. Add or revoke at any time." />
74
- <Item emoji="πŸ›‘" title="Kill switch" body="One click and the agent is revoked everywhere. Existing tokens stop working immediately." />
75
- <Item emoji="πŸ“œ" title="Audit log" body="Every action is logged with timestamp, capability used, and signature. Prove what happened." />
76
- <Item emoji="πŸ”" title="Public verification" body="Anyone can hit githat.io/verify/agent/<wallet> and see the agent's status, capabilities, and recent actions." />
77
- </ul>
78
- </div>
79
- </section>
19
+ <div style=\{{
20
+ position: 'relative',
21
+ width: '100%',
22
+ aspectRatio: '4 / 3',
23
+ borderRadius: '1rem',
24
+ border: '2px dashed var(--border)',
25
+ background: 'var(--surface)',
26
+ display: 'flex',
27
+ flexDirection: 'column',
28
+ alignItems: 'center',
29
+ justifyContent: 'center',
30
+ gap: '0.75rem',
31
+ color: 'var(--fg-muted)',
32
+ }}>
33
+ <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" aria-hidden>
34
+ <rect x="3" y="3" width="18" height="18" rx="2" />
35
+ <circle cx="8.5" cy="8.5" r="1.5" />
36
+ <path d="m21 15-5-5L5 21" />
37
+ </svg>
38
+ <p style=\{{ fontSize: '0.8125rem', textAlign: 'center', lineHeight: 1.5, maxWidth: '16rem' }}>
39
+ Drop your hero image in <code style=\{{ fontFamily: 'var(--font-mono)' }}>public/</code>
40
+ <br />See <code style=\{{ fontFamily: 'var(--font-mono)' }}>public/HERO_IMAGE.md</code>
41
+ </p>
80
42
  </div>
81
43
  );
82
44
  }
83
45
 
84
- function Item({ emoji, title, body }: { emoji: string; title: string; body: string }) {
46
+ function FeatureItem({ emoji, title, body }{{#if typescript}}: { emoji: string; title: string; body: string }{{/if}}) {
85
47
  return (
86
48
  <li style=\{{
87
49
  display: 'flex',
88
50
  gap: 'var(--space-4)',
89
51
  padding: 'var(--space-4)',
90
- borderRadius: 'var(--radius-md, 0.5rem)',
52
+ borderRadius: 'var(--radius-md)',
91
53
  background: 'var(--surface)',
92
54
  }}>
93
55
  <span style=\{{ fontSize: '1.5rem' }} aria-hidden>{emoji}</span>
@@ -98,3 +60,98 @@ function Item({ emoji, title, body }: { emoji: string; title: string; body: stri
98
60
  </li>
99
61
  );
100
62
  }
63
+
64
+ export default function Home() {
65
+ const { isSignedIn } = useAuth();
66
+
67
+ return (
68
+ <div style=\{{ background: 'var(--bg)', color: 'var(--fg)', minHeight: 'calc(100vh - 64px)' }}>
69
+
70
+ {/* Hero β€” split layout */}
71
+ <section style=\{{
72
+ display: 'grid',
73
+ gridTemplateColumns: 'repeat(auto-fit, minmax(18rem, 1fr))',
74
+ gap: 'var(--space-12)',
75
+ alignItems: 'center',
76
+ padding: 'var(--space-12) var(--space-6)',
77
+ maxWidth: '72rem',
78
+ margin: '0 auto',
79
+ }}>
80
+ {/* Left β€” pitch */}
81
+ <div>
82
+ <h1 style=\{{
83
+ fontFamily: 'var(--font-wordmark)',
84
+ fontSize: 'clamp(2rem, 5vw, 3.25rem)',
85
+ lineHeight: 1.1,
86
+ marginBottom: 'var(--space-4)',
87
+ }}>
88
+ {{businessName}}
89
+ </h1>
90
+ <p style=\{{ color: 'var(--fg-muted)', fontSize: '1.125rem', lineHeight: 1.6, marginBottom: 'var(--space-6)', maxWidth: '32rem' }}>
91
+ Wallet-bound identity for autonomous AI agents. Capability
92
+ scoping, kill switch, audit trail β€” and a public{' '}
93
+ <code style=\{{ fontSize: '0.9em', fontFamily: 'var(--font-mono)' }}>/verify</code>{' '}
94
+ endpoint anyone can hit.
95
+ </p>
96
+ {!isSignedIn ? (
97
+ <div style=\{{ display: 'flex', gap: 'var(--space-3)', flexWrap: 'wrap' }}>
98
+ <Link href="/sign-up" style=\{{
99
+ display: 'inline-block',
100
+ padding: 'var(--space-3) var(--space-6)',
101
+ borderRadius: 'var(--radius-md)',
102
+ background: 'var(--primary)',
103
+ color: '#fff',
104
+ fontWeight: 600,
105
+ textDecoration: 'none',
106
+ }}>
107
+ Register an agent β†’
108
+ </Link>
109
+ <Link href="/sign-in" style=\{{
110
+ display: 'inline-block',
111
+ padding: 'var(--space-3) var(--space-6)',
112
+ borderRadius: 'var(--radius-md)',
113
+ border: '1px solid var(--border)',
114
+ color: 'var(--fg)',
115
+ fontWeight: 600,
116
+ textDecoration: 'none',
117
+ }}>
118
+ Sign in
119
+ </Link>
120
+ </div>
121
+ ) : (
122
+ <Link href="/dashboard" style=\{{
123
+ display: 'inline-block',
124
+ padding: 'var(--space-3) var(--space-6)',
125
+ borderRadius: 'var(--radius-md)',
126
+ background: 'var(--primary)',
127
+ color: '#fff',
128
+ fontWeight: 600,
129
+ textDecoration: 'none',
130
+ }}>
131
+ Open dashboard β†’
132
+ </Link>
133
+ )}
134
+ </div>
135
+
136
+ {/* Right β€” hero image */}
137
+ <div>
138
+ <HeroImagePlaceholder />
139
+ </div>
140
+ </section>
141
+
142
+ {/* Features */}
143
+ <section style=\{{ padding: 'var(--space-12) var(--space-6)', background: 'var(--surface-sub)' }}>
144
+ <div style=\{{ maxWidth: '52rem', margin: '0 auto' }}>
145
+ <h2 style=\{{ fontSize: '1.5rem', marginBottom: 'var(--space-6)' }}>What you get</h2>
146
+ <ul style=\{{ listStyle: 'none', padding: 0, margin: 0, display: 'flex', flexDirection: 'column', gap: 'var(--space-3)' }}>
147
+ <FeatureItem emoji="πŸͺͺ" title="Wallet-bound identity" body="Ethereum-style key pair. The agent signs requests; clients verify the signature. No shared secrets." />
148
+ <FeatureItem emoji="🎚" title="Capability scopes" body="Each agent can only call the tools you explicitly granted. Add or revoke at any time." />
149
+ <FeatureItem emoji="πŸ›‘" title="Kill switch" body="One click and the agent is revoked everywhere. Existing tokens stop working immediately." />
150
+ <FeatureItem emoji="πŸ“œ" title="Audit log" body="Every action is logged with timestamp, capability used, and signature." />
151
+ <FeatureItem emoji="πŸ”" title="Public verification" body="Anyone can hit /verify/agent/<wallet> and see the agent's current status and capabilities." />
152
+ </ul>
153
+ </div>
154
+ </section>
155
+ </div>
156
+ );
157
+ }