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.
- package/dist/cli.js +5 -5
- package/package.json +6 -2
- package/templates/agent/app/(auth)/forgot-password/page.tsx.hbs +11 -0
- package/templates/agent/app/(auth)/reset-password/page.tsx.hbs +39 -0
- package/templates/agent/app/(auth)/verify-email/page.tsx.hbs +41 -0
- package/templates/agent/app/admin/agent/page.tsx.hbs +159 -62
- package/templates/agent/app/admin/layout.tsx.hbs +82 -0
- package/templates/agent/app/admin/mcp/page.tsx.hbs +156 -0
- package/templates/agent/app/dashboard/agents/page.tsx.hbs +9 -0
- package/templates/agent/app/dashboard/layout.tsx.hbs +9 -0
- package/templates/agent/app/dashboard/mcp/page.tsx.hbs +9 -0
- package/templates/agent/app/dashboard/page.tsx.hbs +128 -0
- package/templates/agent/app/globals.css.hbs +14 -9
- package/templates/agent/app/layout.tsx.hbs +7 -1
- package/templates/agent/app/page.tsx.hbs +127 -70
- package/templates/agent/app/verify/agent/page.tsx.hbs +124 -0
- package/templates/agent/next.config.ts.hbs +4 -5
- package/templates/agent/public/HERO_IMAGE.md +23 -0
- package/templates/base/githat/api/agents.ts.hbs +6 -6
- package/templates/base/githat/config.ts.hbs +7 -2
- package/templates/base/githat/dashboard/overview.tsx.hbs +106 -16
- package/templates/classroom/app/layout.tsx.hbs +6 -0
- package/templates/classroom/next.config.ts.hbs +4 -5
- package/templates/content/app/layout.tsx.hbs +6 -0
- package/templates/content/next.config.ts.hbs +4 -5
- package/templates/dashboard/app/admin/data/[entity]/page.tsx.hbs +2 -2
- package/templates/dashboard/app/layout.tsx.hbs +6 -0
- package/templates/dashboard/next.config.ts.hbs +4 -5
- package/templates/fullstack/apps-web-nextjs/app/layout.tsx.hbs +6 -0
- package/templates/fullstack/apps-web-nextjs/next.config.ts.hbs +5 -5
- package/templates/marketplace/app/layout.tsx.hbs +6 -0
- package/templates/marketplace/next.config.ts.hbs +4 -5
- package/templates/nextjs/app/(auth)/forgot-password/page.tsx.hbs +2 -54
- package/templates/nextjs/app/(auth)/reset-password/page.tsx.hbs +8 -75
- package/templates/nextjs/app/layout.tsx.hbs +6 -0
- package/templates/nextjs/next.config.ts.hbs +4 -5
- package/templates/plain/app/layout.tsx.hbs +6 -0
- package/templates/plain/next.config.ts.hbs +4 -5
- package/templates/portfolio/app/layout.tsx.hbs +6 -0
- package/templates/portfolio/next.config.ts.hbs +4 -5
- package/templates/saas/app/layout.tsx.hbs +6 -0
- package/templates/saas/next.config.ts.hbs +4 -5
- package/templates/agent/proxy.ts.hbs +0 -10
- package/templates/classroom/proxy.ts.hbs +0 -10
- package/templates/content/proxy.ts.hbs +0 -10
- package/templates/dashboard/proxy.ts.hbs +0 -10
- package/templates/marketplace/app/(shop)/[slug]/p/[productId]/page.tsx.hbs +0 -99
- package/templates/marketplace/app/(shop)/[slug]/page.tsx.hbs +0 -90
- package/templates/marketplace/proxy.ts.hbs +0 -10
- package/templates/nextjs/proxy.ts.hbs +0 -10
- package/templates/plain/proxy.ts.hbs +0 -10
- package/templates/portfolio/proxy.ts.hbs +0 -10
- 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 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:
|
|
43
|
-
--space-2:
|
|
44
|
-
--space-3:
|
|
45
|
-
--space-4:
|
|
46
|
-
--space-
|
|
47
|
-
--space-
|
|
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:
|
|
51
|
-
--radius-md:
|
|
52
|
-
--radius-lg:
|
|
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
|
-
*
|
|
7
|
+
* Landing page β split-hero layout.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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
|
-
*
|
|
15
|
-
*
|
|
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=\{{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
{
|
|
42
|
-
|
|
43
|
-
|
|
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
|
|
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
|
|
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
|
+
}
|