create-githat-app 1.0.14 → 1.0.16
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 +72 -18
- package/package.json +1 -1
- package/templates/agent/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/agent/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/agent/app/admin/agent/page.tsx.hbs +127 -0
- package/templates/agent/app/globals.css.hbs +87 -0
- package/templates/agent/app/layout.tsx.hbs +41 -0
- package/templates/agent/app/page.tsx.hbs +100 -0
- package/templates/agent/next.config.ts.hbs +7 -0
- package/templates/agent/postcss.config.mjs.hbs +14 -0
- package/templates/agent/proxy.ts.hbs +10 -0
- package/templates/agent/tsconfig.json.hbs +21 -0
- package/templates/classroom/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/classroom/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/classroom/app/globals.css.hbs +87 -0
- package/templates/classroom/app/layout.tsx.hbs +41 -0
- package/templates/classroom/app/page.tsx.hbs +103 -0
- package/templates/classroom/app/projects/[id]/feedback/page.tsx.hbs +159 -0
- package/templates/classroom/app/projects/[id]/present/page.tsx.hbs +113 -0
- package/templates/classroom/next.config.ts.hbs +7 -0
- package/templates/classroom/postcss.config.mjs.hbs +14 -0
- package/templates/classroom/proxy.ts.hbs +10 -0
- package/templates/classroom/tsconfig.json.hbs +21 -0
- package/templates/content/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/content/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/content/app/globals.css.hbs +87 -0
- package/templates/content/app/layout.tsx.hbs +41 -0
- package/templates/content/app/newsletter/page.tsx.hbs +90 -0
- package/templates/content/app/page.tsx.hbs +105 -0
- package/templates/content/app/posts/[slug]/page.tsx.hbs +119 -0
- package/templates/content/next.config.ts.hbs +7 -0
- package/templates/content/postcss.config.mjs.hbs +14 -0
- package/templates/content/proxy.ts.hbs +10 -0
- package/templates/content/tsconfig.json.hbs +21 -0
- package/templates/dashboard/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/dashboard/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/dashboard/app/admin/data/[entity]/page.tsx.hbs +68 -0
- package/templates/dashboard/app/admin/page.tsx.hbs +59 -0
- package/templates/dashboard/app/globals.css.hbs +87 -0
- package/templates/dashboard/app/layout.tsx.hbs +41 -0
- package/templates/dashboard/app/page.tsx.hbs +57 -0
- package/templates/dashboard/next.config.ts.hbs +7 -0
- package/templates/dashboard/postcss.config.mjs.hbs +14 -0
- package/templates/dashboard/proxy.ts.hbs +10 -0
- package/templates/dashboard/src/lib/db.ts.hbs +39 -0
- package/templates/dashboard/tsconfig.json.hbs +21 -0
- package/templates/marketplace/CULTURE.md +74 -0
- package/templates/marketplace/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/marketplace/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/marketplace/app/(shop)/[slug]/p/[productId]/page.tsx.hbs +99 -0
- package/templates/marketplace/app/(shop)/[slug]/page.tsx.hbs +90 -0
- package/templates/marketplace/app/admin/page.tsx.hbs +95 -0
- package/templates/marketplace/app/cart/page.tsx.hbs +157 -0
- package/templates/marketplace/app/globals.css.hbs +87 -0
- package/templates/marketplace/app/layout.tsx.hbs +77 -0
- package/templates/marketplace/app/page.tsx.hbs +178 -0
- package/templates/marketplace/app/sell/page.tsx.hbs +78 -0
- package/templates/marketplace/next.config.ts.hbs +7 -0
- package/templates/marketplace/postcss.config.mjs.hbs +14 -0
- package/templates/marketplace/proxy.ts.hbs +10 -0
- package/templates/marketplace/src/lib/anon-session.ts.hbs +117 -0
- package/templates/marketplace/src/lib/categories.ts.hbs +35 -0
- package/templates/marketplace/tsconfig.json.hbs +21 -0
- package/templates/portfolio/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/portfolio/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/portfolio/app/globals.css.hbs +87 -0
- package/templates/portfolio/app/layout.tsx.hbs +41 -0
- package/templates/portfolio/app/page.tsx.hbs +86 -0
- package/templates/portfolio/next.config.ts.hbs +7 -0
- package/templates/portfolio/postcss.config.mjs.hbs +14 -0
- package/templates/portfolio/proxy.ts.hbs +10 -0
- package/templates/portfolio/tsconfig.json.hbs +21 -0
- package/templates/saas/app/(auth)/sign-in/page.tsx.hbs +9 -0
- package/templates/saas/app/(auth)/sign-up/page.tsx.hbs +9 -0
- package/templates/saas/app/admin/billing/page.tsx.hbs +145 -0
- package/templates/saas/app/admin/page.tsx.hbs +106 -0
- package/templates/saas/app/admin/team/page.tsx.hbs +134 -0
- package/templates/saas/app/globals.css.hbs +87 -0
- package/templates/saas/app/layout.tsx.hbs +41 -0
- package/templates/saas/app/page.tsx.hbs +108 -0
- package/templates/saas/app/pricing/page.tsx.hbs +131 -0
- package/templates/saas/next.config.ts.hbs +7 -0
- package/templates/saas/postcss.config.mjs.hbs +14 -0
- package/templates/saas/proxy.ts.hbs +10 -0
- package/templates/saas/tsconfig.json.hbs +21 -0
package/dist/cli.js
CHANGED
|
@@ -11,7 +11,7 @@ import gradient from "gradient-string";
|
|
|
11
11
|
import chalk from "chalk";
|
|
12
12
|
|
|
13
13
|
// src/constants.ts
|
|
14
|
-
var VERSION = "1.0.
|
|
14
|
+
var VERSION = "1.0.16";
|
|
15
15
|
var DEFAULT_API_URL = "https://api.githat.io";
|
|
16
16
|
var DASHBOARD_URL = "https://githat.io/dashboard/apps";
|
|
17
17
|
var BRAND_COLORS = ["#7c3aed", "#6366f1", "#8b5cf6"];
|
|
@@ -330,9 +330,16 @@ function getInstallCommand(pm) {
|
|
|
330
330
|
async function promptFramework(typescriptOverride, isFullstack) {
|
|
331
331
|
const packageManager = detectPackageManager();
|
|
332
332
|
const frameworkOptions = isFullstack ? [{ value: "nextjs", label: "Next.js 16", hint: "App Router \xB7 SSR \xB7 middleware auth" }] : [
|
|
333
|
-
{ value: "plain", label: "Plain
|
|
334
|
-
{ value: "
|
|
335
|
-
{ value: "
|
|
333
|
+
{ value: "plain", label: "Plain", hint: "Auth + a homepage. Smallest possible GitHat app." },
|
|
334
|
+
{ value: "saas", label: "SaaS", hint: "Orgs, teams, RBAC, subscription billing. Replaces Clerk + Stripe." },
|
|
335
|
+
{ value: "marketplace", label: "Marketplace", hint: "Multi-vendor commerce. Anonymous-first, Sebastn Connect." },
|
|
336
|
+
{ value: "content", label: "Content", hint: "Paywalled posts, newsletter. Replaces Substack." },
|
|
337
|
+
{ value: "dashboard", label: "Dashboard", hint: "Auth-gated admin UI over your existing database." },
|
|
338
|
+
{ value: "portfolio", label: "Portfolio", hint: "Personal site: public projects, auth-gated editor." },
|
|
339
|
+
{ value: "classroom", label: "Classroom", hint: "Live student presentations + real-time audience feedback." },
|
|
340
|
+
{ value: "agent", label: "AI Agent", hint: "Web4 wallet-bound agent + MCP server. Public verification." },
|
|
341
|
+
{ value: "nextjs", label: "Next.js (full kit)", hint: "Legacy: dashboard + orgs + agents + MCP scaffolding." },
|
|
342
|
+
{ value: "react-vite", label: "React + Vite", hint: "SPA \xB7 client-side routing." }
|
|
336
343
|
];
|
|
337
344
|
const answers = await p3.group(
|
|
338
345
|
{
|
|
@@ -584,10 +591,11 @@ async function promptFinalize() {
|
|
|
584
591
|
function toDisplayName(projectName) {
|
|
585
592
|
return projectName.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
586
593
|
}
|
|
587
|
-
function getDefaults(projectName, publishableKey, typescript, fullstack, backendFramework,
|
|
594
|
+
function getDefaults(projectName, publishableKey, typescript, fullstack, backendFramework, template) {
|
|
588
595
|
const displayName = toDisplayName(projectName);
|
|
589
596
|
const projectType = fullstack ? "fullstack" : "frontend";
|
|
590
|
-
const framework =
|
|
597
|
+
const framework = template ?? "nextjs";
|
|
598
|
+
const isMinimal = template !== void 0;
|
|
591
599
|
return {
|
|
592
600
|
projectName,
|
|
593
601
|
businessName: displayName,
|
|
@@ -599,19 +607,21 @@ function getDefaults(projectName, publishableKey, typescript, fullstack, backend
|
|
|
599
607
|
packageManager: detectPackageManager(),
|
|
600
608
|
publishableKey: publishableKey || "",
|
|
601
609
|
apiUrl: DEFAULT_API_URL,
|
|
602
|
-
authFeatures:
|
|
610
|
+
authFeatures: isMinimal ? [] : ["forgot-password"],
|
|
603
611
|
databaseChoice: "none",
|
|
604
612
|
useTailwind: true,
|
|
605
|
-
includeDashboard: !
|
|
606
|
-
includeGithatFolder: !
|
|
613
|
+
includeDashboard: !isMinimal,
|
|
614
|
+
includeGithatFolder: !isMinimal && projectType === "frontend",
|
|
607
615
|
initGit: true,
|
|
608
616
|
installDeps: true
|
|
609
617
|
};
|
|
610
618
|
}
|
|
611
619
|
async function runPrompts(args) {
|
|
612
620
|
if (args.yes && args.initialName) {
|
|
613
|
-
p8.log.info(
|
|
614
|
-
|
|
621
|
+
p8.log.info(
|
|
622
|
+
args.template ? `Using ${args.template} defaults (--yes --${args.template})` : "Using defaults (--yes flag)"
|
|
623
|
+
);
|
|
624
|
+
return getDefaults(args.initialName, args.publishableKey, args.typescript, args.fullstack, args.backendFramework, args.template);
|
|
615
625
|
}
|
|
616
626
|
p8.intro("Let's set up your GitHat app");
|
|
617
627
|
sectionHeader("Project");
|
|
@@ -678,8 +688,19 @@ var TEMPLATES_ROOT = path.resolve(__dirname2, "..", "templates");
|
|
|
678
688
|
Handlebars.registerHelper("ifEquals", function(a, b, options) {
|
|
679
689
|
return a === b ? options.fn(this) : options.inverse(this);
|
|
680
690
|
});
|
|
691
|
+
var NEXT_LIKE = /* @__PURE__ */ new Set([
|
|
692
|
+
"nextjs",
|
|
693
|
+
"plain",
|
|
694
|
+
"saas",
|
|
695
|
+
"marketplace",
|
|
696
|
+
"agent",
|
|
697
|
+
"content",
|
|
698
|
+
"dashboard",
|
|
699
|
+
"portfolio",
|
|
700
|
+
"classroom"
|
|
701
|
+
]);
|
|
681
702
|
Handlebars.registerHelper("ifNext", function(framework, options) {
|
|
682
|
-
return framework
|
|
703
|
+
return NEXT_LIKE.has(framework) ? options.fn(this) : options.inverse(this);
|
|
683
704
|
});
|
|
684
705
|
function getTemplatesRoot() {
|
|
685
706
|
return TEMPLATES_ROOT;
|
|
@@ -727,18 +748,39 @@ function writeJson(root, relativePath, data) {
|
|
|
727
748
|
}
|
|
728
749
|
|
|
729
750
|
// src/scaffold/package-builder.ts
|
|
751
|
+
var NEXT_LIKE2 = /* @__PURE__ */ new Set([
|
|
752
|
+
"nextjs",
|
|
753
|
+
"plain",
|
|
754
|
+
"saas",
|
|
755
|
+
"marketplace",
|
|
756
|
+
"agent",
|
|
757
|
+
"content",
|
|
758
|
+
"dashboard",
|
|
759
|
+
"portfolio",
|
|
760
|
+
"classroom"
|
|
761
|
+
]);
|
|
762
|
+
var MINIMAL = /* @__PURE__ */ new Set([
|
|
763
|
+
"plain",
|
|
764
|
+
"saas",
|
|
765
|
+
"marketplace",
|
|
766
|
+
"agent",
|
|
767
|
+
"content",
|
|
768
|
+
"dashboard",
|
|
769
|
+
"portfolio",
|
|
770
|
+
"classroom"
|
|
771
|
+
]);
|
|
730
772
|
function buildPackageJson(ctx) {
|
|
731
|
-
const isNext =
|
|
773
|
+
const isNext = NEXT_LIKE2.has(ctx.framework);
|
|
732
774
|
const deps = {
|
|
733
775
|
...isNext ? DEPS.nextjs.dependencies : DEPS["react-vite"].dependencies
|
|
734
776
|
};
|
|
735
777
|
const devDeps = {
|
|
736
778
|
...isNext ? DEPS.nextjs.devDependencies : DEPS["react-vite"].devDependencies
|
|
737
779
|
};
|
|
738
|
-
if (ctx.framework
|
|
780
|
+
if (MINIMAL.has(ctx.framework)) {
|
|
739
781
|
delete deps["@githat/ui"];
|
|
740
782
|
}
|
|
741
|
-
if (ctx.useTailwind || ctx.framework
|
|
783
|
+
if (ctx.useTailwind || MINIMAL.has(ctx.framework)) {
|
|
742
784
|
if (isNext) {
|
|
743
785
|
Object.assign(devDeps, DEPS.tailwind.devDependencies);
|
|
744
786
|
} else {
|
|
@@ -932,7 +974,18 @@ async function scaffold(context, options) {
|
|
|
932
974
|
writeJson(root, "package.json", pkg);
|
|
933
975
|
}, "package.json generated");
|
|
934
976
|
}
|
|
935
|
-
|
|
977
|
+
const NEXT_LIKE3 = /* @__PURE__ */ new Set([
|
|
978
|
+
"nextjs",
|
|
979
|
+
"plain",
|
|
980
|
+
"saas",
|
|
981
|
+
"marketplace",
|
|
982
|
+
"agent",
|
|
983
|
+
"content",
|
|
984
|
+
"dashboard",
|
|
985
|
+
"portfolio",
|
|
986
|
+
"classroom"
|
|
987
|
+
]);
|
|
988
|
+
if (!isFullstack && NEXT_LIKE3.has(context.framework)) {
|
|
936
989
|
await registerApp(context.projectName, root);
|
|
937
990
|
}
|
|
938
991
|
if (options.initGit) {
|
|
@@ -1587,7 +1640,7 @@ skillsCommand.action(() => {
|
|
|
1587
1640
|
// src/cli.ts
|
|
1588
1641
|
var program = new Command7();
|
|
1589
1642
|
program.name("githat").description("GitHat CLI - Scaffold apps and manage skills").version(VERSION);
|
|
1590
|
-
program.command("create [project-name]", { isDefault: true }).description("Scaffold a new GitHat app").option("--key <key>", "GitHat publishable key (pk_live_...)").option("--ts", "Use TypeScript (default)").option("--js", "Use JavaScript").option("--plain", "Smallest scaffold: auth + a homepage. No dashboard,
|
|
1643
|
+
program.command("create [project-name]", { isDefault: true }).description("Scaffold a new GitHat app").option("--key <key>", "GitHat publishable key (pk_live_...)").option("--ts", "Use TypeScript (default)").option("--js", "Use JavaScript").option("--plain", "Smallest scaffold: auth + a homepage. No dashboard.").option("--saas", "B2B starter: orgs, teams, RBAC, subscription billing.").option("--marketplace", "Multi-vendor commerce: anonymous-first browsing, Sebastn Connect.").option("--agent", "Web4 wallet-bound autonomous agent + MCP server registration.").option("--content", "Paywalled posts, newsletter, one-time purchases via Sebastn.").option("--dashboard", "Admin UI over your existing database, auth-gated.").option("--portfolio", "Personal portfolio: public projects, auth-gated editor.").option("--classroom", "Live student presentations with real-time audience feedback.").option("--fullstack", "Create fullstack project (Turborepo)").option("--backend <framework>", "Backend framework (hono, express, fastify)").option("-y, --yes", "Skip prompts and use defaults").action(async (projectName, opts) => {
|
|
1591
1644
|
try {
|
|
1592
1645
|
displayBanner();
|
|
1593
1646
|
if (!opts.yes && !opts.key) {
|
|
@@ -1613,12 +1666,13 @@ program.command("create [project-name]", { isDefault: true }).description("Scaff
|
|
|
1613
1666
|
p12.cancel(chalk10.red("Project name is required when using --yes flag"));
|
|
1614
1667
|
process.exit(1);
|
|
1615
1668
|
}
|
|
1669
|
+
const template = opts.marketplace ? "marketplace" : opts.classroom ? "classroom" : opts.portfolio ? "portfolio" : opts.agent ? "agent" : opts.saas ? "saas" : opts.content ? "content" : opts.dashboard ? "dashboard" : opts.plain ? "plain" : void 0;
|
|
1616
1670
|
const answers = await runPrompts({
|
|
1617
1671
|
initialName: projectName,
|
|
1618
1672
|
publishableKey: opts.key,
|
|
1619
1673
|
typescript,
|
|
1620
1674
|
yes: opts.yes,
|
|
1621
|
-
|
|
1675
|
+
template,
|
|
1622
1676
|
fullstack: opts.fullstack,
|
|
1623
1677
|
backendFramework: opts.backend
|
|
1624
1678
|
});
|
package/package.json
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SignInForm } from '@githat/nextjs';
|
|
2
|
+
|
|
3
|
+
export default function SignInPage() {
|
|
4
|
+
return (
|
|
5
|
+
<main {{#if useTailwind}}className="flex items-center justify-center min-h-screen bg-[#09090b]"{{else}}style=\{{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', background: '#09090b' }}{{/if}}>
|
|
6
|
+
<SignInForm signUpUrl="/sign-up" {{#if includeForgotPassword}}forgotPasswordUrl="/forgot-password"{{/if}} />
|
|
7
|
+
</main>
|
|
8
|
+
);
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SignUpForm } from '@githat/nextjs';
|
|
2
|
+
|
|
3
|
+
export default function SignUpPage() {
|
|
4
|
+
return (
|
|
5
|
+
<main {{#if useTailwind}}className="flex items-center justify-center min-h-screen bg-[#09090b]"{{else}}style=\{{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', background: '#09090b' }}{{/if}}>
|
|
6
|
+
<SignUpForm signInUrl="/sign-in" />
|
|
7
|
+
</main>
|
|
8
|
+
);
|
|
9
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import Link from 'next/link';
|
|
4
|
+
import { useAuth } from '@githat/nextjs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Agent operator dashboard — control the agent you registered.
|
|
8
|
+
*
|
|
9
|
+
* Three core actions an operator does:
|
|
10
|
+
* 1. See live status (active / paused / revoked)
|
|
11
|
+
* 2. Adjust capabilities (which tools the agent can call)
|
|
12
|
+
* 3. Hit the kill switch
|
|
13
|
+
*
|
|
14
|
+
* Real apps fetch the agent record from GitHat's
|
|
15
|
+
* GET /agent/{walletAddress}. Stub below shows the data shape.
|
|
16
|
+
*/
|
|
17
|
+
export default function AgentAdminPage() {
|
|
18
|
+
const { isSignedIn, isLoading } = useAuth();
|
|
19
|
+
|
|
20
|
+
if (isLoading) return <div style=\{{ padding: 'var(--space-8)', color: 'var(--fg-muted)' }}>Loading…</div>;
|
|
21
|
+
if (!isSignedIn) {
|
|
22
|
+
return (
|
|
23
|
+
<div style=\{{ padding: 'var(--space-8)', textAlign: 'center' }}>
|
|
24
|
+
<Link href="/sign-in" style=\{{ color: 'var(--primary)' }}>Sign in →</Link>
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const agent = {
|
|
30
|
+
name: 'My research agent',
|
|
31
|
+
wallet: '0xAB12…CDEf',
|
|
32
|
+
status: 'active' as 'active' | 'paused' | 'revoked',
|
|
33
|
+
capabilities: ['web.search', 'web.fetch', 'arxiv.read'],
|
|
34
|
+
actionsLast24h: 47,
|
|
35
|
+
verifyUrl: 'https://githat.io/verify/agent/0xAB12...CDEf',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div style=\{{ padding: 'var(--space-8) var(--space-4)', maxWidth: '48rem', margin: '0 auto' }}>
|
|
40
|
+
<h1 style=\{{ fontFamily: 'var(--font-wordmark)', fontSize: '2rem', marginBottom: 'var(--space-2)' }}>
|
|
41
|
+
{agent.name}
|
|
42
|
+
</h1>
|
|
43
|
+
<p style=\{{ color: 'var(--fg-muted)', fontSize: '0.875rem', marginBottom: 'var(--space-6)' }}>
|
|
44
|
+
Wallet: <code>{agent.wallet}</code>
|
|
45
|
+
</p>
|
|
46
|
+
|
|
47
|
+
<section style=\{{
|
|
48
|
+
padding: 'var(--space-5)',
|
|
49
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
50
|
+
border: '1px solid var(--border)',
|
|
51
|
+
background: 'var(--surface)',
|
|
52
|
+
marginBottom: 'var(--space-6)',
|
|
53
|
+
}}>
|
|
54
|
+
<div style=\{{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 'var(--space-3)' }}>
|
|
55
|
+
<span style=\{{ fontSize: '0.875rem', color: 'var(--fg-muted)' }}>Status</span>
|
|
56
|
+
<span style=\{{
|
|
57
|
+
padding: 'var(--space-1) var(--space-3)',
|
|
58
|
+
borderRadius: 'var(--radius-full, 9999px)',
|
|
59
|
+
background: agent.status === 'active' ? 'var(--success)' : agent.status === 'paused' ? 'var(--warn)' : 'var(--danger)',
|
|
60
|
+
color: 'var(--bg)',
|
|
61
|
+
fontSize: '0.75rem',
|
|
62
|
+
fontWeight: 700,
|
|
63
|
+
}}>
|
|
64
|
+
{agent.status.toUpperCase()}
|
|
65
|
+
</span>
|
|
66
|
+
</div>
|
|
67
|
+
<div style=\{{ fontSize: '2rem', fontWeight: 600, marginBottom: 'var(--space-1)' }}>
|
|
68
|
+
{agent.actionsLast24h}
|
|
69
|
+
</div>
|
|
70
|
+
<div style=\{{ fontSize: '0.75rem', color: 'var(--fg-subtle)' }}>actions in the last 24 hours</div>
|
|
71
|
+
</section>
|
|
72
|
+
|
|
73
|
+
<section style=\{{ marginBottom: 'var(--space-6)' }}>
|
|
74
|
+
<h2 style=\{{ fontSize: '1.125rem', marginBottom: 'var(--space-3)' }}>Capabilities</h2>
|
|
75
|
+
<ul style=\{{ listStyle: 'none', padding: 0, margin: 0, display: 'flex', flexWrap: 'wrap', gap: 'var(--space-2)' }}>
|
|
76
|
+
{agent.capabilities.map((cap) => (
|
|
77
|
+
<li key={cap} style=\{{
|
|
78
|
+
padding: 'var(--space-2) var(--space-3)',
|
|
79
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
80
|
+
border: '1px solid var(--border)',
|
|
81
|
+
background: 'var(--surface)',
|
|
82
|
+
fontSize: '0.875rem',
|
|
83
|
+
fontFamily: 'var(--font-mono, monospace)',
|
|
84
|
+
}}>
|
|
85
|
+
{cap}
|
|
86
|
+
</li>
|
|
87
|
+
))}
|
|
88
|
+
</ul>
|
|
89
|
+
</section>
|
|
90
|
+
|
|
91
|
+
<section style=\{{ display: 'flex', gap: 'var(--space-3)', flexWrap: 'wrap' }}>
|
|
92
|
+
<a href={agent.verifyUrl} target="_blank" rel="noopener noreferrer" style=\{{
|
|
93
|
+
padding: 'var(--space-3) var(--space-4)',
|
|
94
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
95
|
+
border: '1px solid var(--border)',
|
|
96
|
+
color: 'var(--fg)',
|
|
97
|
+
textDecoration: 'none',
|
|
98
|
+
}}>
|
|
99
|
+
Public verify URL ↗
|
|
100
|
+
</a>
|
|
101
|
+
<Link href="/admin/mcp" style=\{{
|
|
102
|
+
padding: 'var(--space-3) var(--space-4)',
|
|
103
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
104
|
+
border: '1px solid var(--border)',
|
|
105
|
+
color: 'var(--fg)',
|
|
106
|
+
textDecoration: 'none',
|
|
107
|
+
}}>
|
|
108
|
+
MCP servers
|
|
109
|
+
</Link>
|
|
110
|
+
<button
|
|
111
|
+
onClick={() => { /* TODO: POST /api/agent/kill */ }}
|
|
112
|
+
style=\{{
|
|
113
|
+
padding: 'var(--space-3) var(--space-4)',
|
|
114
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
115
|
+
border: '1px solid var(--danger)',
|
|
116
|
+
background: 'transparent',
|
|
117
|
+
color: 'var(--danger)',
|
|
118
|
+
fontWeight: 600,
|
|
119
|
+
cursor: 'pointer',
|
|
120
|
+
}}
|
|
121
|
+
>
|
|
122
|
+
Kill switch
|
|
123
|
+
</button>
|
|
124
|
+
</section>
|
|
125
|
+
</div>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Tailwind v4 — required because @githat/nextjs/styles is processed
|
|
3
|
+
* through @tailwindcss/postcss. Plain doesn't ship utility classes,
|
|
4
|
+
* but the import is needed for the auth pages to render styled.
|
|
5
|
+
*/
|
|
6
|
+
@import "tailwindcss";
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* Plain template — self-contained globals.
|
|
10
|
+
*
|
|
11
|
+
* Defines the minimum CSS variables a GitHat app uses for layout and
|
|
12
|
+
* the auth-page styling that ships with @githat/nextjs/styles.
|
|
13
|
+
* Override these in your own files when you want a real theme.
|
|
14
|
+
*
|
|
15
|
+
* Light theme by default; flip --bg/--fg for dark.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
:root {
|
|
19
|
+
/* Surface */
|
|
20
|
+
--bg: #ffffff;
|
|
21
|
+
--surface: #fafafa;
|
|
22
|
+
--surface-sub: #f4f4f5;
|
|
23
|
+
|
|
24
|
+
/* Borders */
|
|
25
|
+
--border: #e5e7eb;
|
|
26
|
+
|
|
27
|
+
/* Foreground */
|
|
28
|
+
--fg: #0a0a0a;
|
|
29
|
+
--fg-muted: #525252;
|
|
30
|
+
--fg-subtle: #737373;
|
|
31
|
+
|
|
32
|
+
/* Brand — change these two to re-skin the whole auth flow */
|
|
33
|
+
--primary: #6366f1;
|
|
34
|
+
--accent: #f59e0b;
|
|
35
|
+
|
|
36
|
+
/* Semantic */
|
|
37
|
+
--success: #16a34a;
|
|
38
|
+
--warn: #d97706;
|
|
39
|
+
--danger: #dc2626;
|
|
40
|
+
|
|
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;
|
|
48
|
+
|
|
49
|
+
/* Radius */
|
|
50
|
+
--radius: 0.5rem;
|
|
51
|
+
--radius-md: 0.5rem;
|
|
52
|
+
--radius-lg: 0.75rem;
|
|
53
|
+
|
|
54
|
+
/* Fonts */
|
|
55
|
+
--font-sans: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
|
|
56
|
+
--font-wordmark: 'Instrument Serif', Georgia, serif;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@media (prefers-color-scheme: dark) {
|
|
60
|
+
:root {
|
|
61
|
+
--bg: #0a0a0a;
|
|
62
|
+
--surface: #18181b;
|
|
63
|
+
--surface-sub: #27272a;
|
|
64
|
+
--border: #3f3f46;
|
|
65
|
+
--fg: #fafafa;
|
|
66
|
+
--fg-muted: #a1a1aa;
|
|
67
|
+
--fg-subtle: #71717a;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
* {
|
|
72
|
+
box-sizing: border-box;
|
|
73
|
+
margin: 0;
|
|
74
|
+
padding: 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
body {
|
|
78
|
+
font-family: var(--font-sans);
|
|
79
|
+
background: var(--bg);
|
|
80
|
+
color: var(--fg);
|
|
81
|
+
line-height: 1.5;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
a {
|
|
85
|
+
color: inherit;
|
|
86
|
+
text-decoration: none;
|
|
87
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { GitHatProvider } from '@githat/nextjs';
|
|
2
|
+
import '@githat/nextjs/styles';
|
|
3
|
+
import './globals.css';
|
|
4
|
+
|
|
5
|
+
export const metadata = {
|
|
6
|
+
title: '{{businessName}}',
|
|
7
|
+
description: '{{description}}',
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default function RootLayout({ children }{{#if typescript}}: { children: React.ReactNode }{{/if}}) {
|
|
11
|
+
return (
|
|
12
|
+
<html lang="en">
|
|
13
|
+
<body>
|
|
14
|
+
{/*
|
|
15
|
+
Plain template: no @githat/ui dep, no Wordmark. The
|
|
16
|
+
full-kit (`nextjs`) template uses @githat/ui for the
|
|
17
|
+
shared design system; the plain scaffold is the smallest
|
|
18
|
+
working app, so we avoid extra deps.
|
|
19
|
+
*/}
|
|
20
|
+
<GitHatProvider config=\{{
|
|
21
|
+
publishableKey: process.env.NEXT_PUBLIC_GITHAT_PUBLISHABLE_KEY || '',
|
|
22
|
+
signInUrl: '/sign-in',
|
|
23
|
+
signUpUrl: '/sign-up',
|
|
24
|
+
afterSignInUrl: '/',
|
|
25
|
+
afterSignOutUrl: '/',
|
|
26
|
+
}}>
|
|
27
|
+
<header style=\{{
|
|
28
|
+
padding: '1rem 1.5rem',
|
|
29
|
+
borderBottom: '1px solid var(--border, #e5e7eb)',
|
|
30
|
+
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
31
|
+
}}>
|
|
32
|
+
<a href="/" style=\{{ textDecoration: 'none', color: 'inherit', fontWeight: 600 }}>
|
|
33
|
+
{{businessName}}
|
|
34
|
+
</a>
|
|
35
|
+
</header>
|
|
36
|
+
<main>{children}</main>
|
|
37
|
+
</GitHatProvider>
|
|
38
|
+
</body>
|
|
39
|
+
</html>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import Link from 'next/link';
|
|
4
|
+
import { useAuth } from '@githat/nextjs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* AI Agent template — Web4 identity, MCP, public verification.
|
|
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>.
|
|
13
|
+
*
|
|
14
|
+
* This template is the agent operator's dashboard, plus the public
|
|
15
|
+
* /verify endpoint anyone can hit to check an agent's status.
|
|
16
|
+
*/
|
|
17
|
+
export default function Home() {
|
|
18
|
+
const { isSignedIn } = useAuth();
|
|
19
|
+
|
|
20
|
+
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>
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function Item({ emoji, title, body }: { emoji: string; title: string; body: string }) {
|
|
85
|
+
return (
|
|
86
|
+
<li style=\{{
|
|
87
|
+
display: 'flex',
|
|
88
|
+
gap: 'var(--space-4)',
|
|
89
|
+
padding: 'var(--space-4)',
|
|
90
|
+
borderRadius: 'var(--radius-md, 0.5rem)',
|
|
91
|
+
background: 'var(--surface)',
|
|
92
|
+
}}>
|
|
93
|
+
<span style=\{{ fontSize: '1.5rem' }} aria-hidden>{emoji}</span>
|
|
94
|
+
<div>
|
|
95
|
+
<div style=\{{ fontWeight: 600, marginBottom: 'var(--space-1)' }}>{title}</div>
|
|
96
|
+
<div style=\{{ fontSize: '0.875rem', color: 'var(--fg-muted)' }}>{body}</div>
|
|
97
|
+
</div>
|
|
98
|
+
</li>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Plain template — Tailwind v4 PostCSS plugin is required even though
|
|
3
|
+
* the plain scaffold doesn't use Tailwind utility classes. The auth
|
|
4
|
+
* page CSS shipped by `@githat/nextjs/styles` is processed through
|
|
5
|
+
* @tailwindcss/postcss at build time. Drop this config and the
|
|
6
|
+
* auth pages render unstyled.
|
|
7
|
+
*/
|
|
8
|
+
const config = {
|
|
9
|
+
plugins: {
|
|
10
|
+
'@tailwindcss/postcss': {},
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default config;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { authProxy } from '@githat/nextjs/proxy';
|
|
2
|
+
|
|
3
|
+
export const proxy = authProxy({
|
|
4
|
+
publicRoutes: ['/', '/sign-in', '/sign-up'{{#if includeForgotPassword}}, '/forgot-password', '/reset-password'{{/if}}{{#if includeEmailVerification}}, '/verify-email'{{/if}}],
|
|
5
|
+
signInUrl: '/sign-in',
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export const config = {
|
|
9
|
+
matcher: ['/((?!_next|api|.*\\..*).*)'],
|
|
10
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2017",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"module": "esnext",
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"jsx": "preserve",
|
|
15
|
+
"incremental": true,
|
|
16
|
+
"plugins": [{ "name": "next" }],
|
|
17
|
+
"paths": { "@/*": ["./*"] }
|
|
18
|
+
},
|
|
19
|
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
20
|
+
"exclude": ["node_modules"]
|
|
21
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SignInForm } from '@githat/nextjs';
|
|
2
|
+
|
|
3
|
+
export default function SignInPage() {
|
|
4
|
+
return (
|
|
5
|
+
<main {{#if useTailwind}}className="flex items-center justify-center min-h-screen bg-[#09090b]"{{else}}style=\{{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', background: '#09090b' }}{{/if}}>
|
|
6
|
+
<SignInForm signUpUrl="/sign-up" {{#if includeForgotPassword}}forgotPasswordUrl="/forgot-password"{{/if}} />
|
|
7
|
+
</main>
|
|
8
|
+
);
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SignUpForm } from '@githat/nextjs';
|
|
2
|
+
|
|
3
|
+
export default function SignUpPage() {
|
|
4
|
+
return (
|
|
5
|
+
<main {{#if useTailwind}}className="flex items-center justify-center min-h-screen bg-[#09090b]"{{else}}style=\{{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', background: '#09090b' }}{{/if}}>
|
|
6
|
+
<SignUpForm signInUrl="/sign-in" />
|
|
7
|
+
</main>
|
|
8
|
+
);
|
|
9
|
+
}
|