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.
Files changed (85) hide show
  1. package/dist/cli.js +72 -18
  2. package/package.json +1 -1
  3. package/templates/agent/app/(auth)/sign-in/page.tsx.hbs +9 -0
  4. package/templates/agent/app/(auth)/sign-up/page.tsx.hbs +9 -0
  5. package/templates/agent/app/admin/agent/page.tsx.hbs +127 -0
  6. package/templates/agent/app/globals.css.hbs +87 -0
  7. package/templates/agent/app/layout.tsx.hbs +41 -0
  8. package/templates/agent/app/page.tsx.hbs +100 -0
  9. package/templates/agent/next.config.ts.hbs +7 -0
  10. package/templates/agent/postcss.config.mjs.hbs +14 -0
  11. package/templates/agent/proxy.ts.hbs +10 -0
  12. package/templates/agent/tsconfig.json.hbs +21 -0
  13. package/templates/classroom/app/(auth)/sign-in/page.tsx.hbs +9 -0
  14. package/templates/classroom/app/(auth)/sign-up/page.tsx.hbs +9 -0
  15. package/templates/classroom/app/globals.css.hbs +87 -0
  16. package/templates/classroom/app/layout.tsx.hbs +41 -0
  17. package/templates/classroom/app/page.tsx.hbs +103 -0
  18. package/templates/classroom/app/projects/[id]/feedback/page.tsx.hbs +159 -0
  19. package/templates/classroom/app/projects/[id]/present/page.tsx.hbs +113 -0
  20. package/templates/classroom/next.config.ts.hbs +7 -0
  21. package/templates/classroom/postcss.config.mjs.hbs +14 -0
  22. package/templates/classroom/proxy.ts.hbs +10 -0
  23. package/templates/classroom/tsconfig.json.hbs +21 -0
  24. package/templates/content/app/(auth)/sign-in/page.tsx.hbs +9 -0
  25. package/templates/content/app/(auth)/sign-up/page.tsx.hbs +9 -0
  26. package/templates/content/app/globals.css.hbs +87 -0
  27. package/templates/content/app/layout.tsx.hbs +41 -0
  28. package/templates/content/app/newsletter/page.tsx.hbs +90 -0
  29. package/templates/content/app/page.tsx.hbs +105 -0
  30. package/templates/content/app/posts/[slug]/page.tsx.hbs +119 -0
  31. package/templates/content/next.config.ts.hbs +7 -0
  32. package/templates/content/postcss.config.mjs.hbs +14 -0
  33. package/templates/content/proxy.ts.hbs +10 -0
  34. package/templates/content/tsconfig.json.hbs +21 -0
  35. package/templates/dashboard/app/(auth)/sign-in/page.tsx.hbs +9 -0
  36. package/templates/dashboard/app/(auth)/sign-up/page.tsx.hbs +9 -0
  37. package/templates/dashboard/app/admin/data/[entity]/page.tsx.hbs +68 -0
  38. package/templates/dashboard/app/admin/page.tsx.hbs +59 -0
  39. package/templates/dashboard/app/globals.css.hbs +87 -0
  40. package/templates/dashboard/app/layout.tsx.hbs +41 -0
  41. package/templates/dashboard/app/page.tsx.hbs +57 -0
  42. package/templates/dashboard/next.config.ts.hbs +7 -0
  43. package/templates/dashboard/postcss.config.mjs.hbs +14 -0
  44. package/templates/dashboard/proxy.ts.hbs +10 -0
  45. package/templates/dashboard/src/lib/db.ts.hbs +39 -0
  46. package/templates/dashboard/tsconfig.json.hbs +21 -0
  47. package/templates/marketplace/CULTURE.md +74 -0
  48. package/templates/marketplace/app/(auth)/sign-in/page.tsx.hbs +9 -0
  49. package/templates/marketplace/app/(auth)/sign-up/page.tsx.hbs +9 -0
  50. package/templates/marketplace/app/(shop)/[slug]/p/[productId]/page.tsx.hbs +99 -0
  51. package/templates/marketplace/app/(shop)/[slug]/page.tsx.hbs +90 -0
  52. package/templates/marketplace/app/admin/page.tsx.hbs +95 -0
  53. package/templates/marketplace/app/cart/page.tsx.hbs +157 -0
  54. package/templates/marketplace/app/globals.css.hbs +87 -0
  55. package/templates/marketplace/app/layout.tsx.hbs +77 -0
  56. package/templates/marketplace/app/page.tsx.hbs +178 -0
  57. package/templates/marketplace/app/sell/page.tsx.hbs +78 -0
  58. package/templates/marketplace/next.config.ts.hbs +7 -0
  59. package/templates/marketplace/postcss.config.mjs.hbs +14 -0
  60. package/templates/marketplace/proxy.ts.hbs +10 -0
  61. package/templates/marketplace/src/lib/anon-session.ts.hbs +117 -0
  62. package/templates/marketplace/src/lib/categories.ts.hbs +35 -0
  63. package/templates/marketplace/tsconfig.json.hbs +21 -0
  64. package/templates/portfolio/app/(auth)/sign-in/page.tsx.hbs +9 -0
  65. package/templates/portfolio/app/(auth)/sign-up/page.tsx.hbs +9 -0
  66. package/templates/portfolio/app/globals.css.hbs +87 -0
  67. package/templates/portfolio/app/layout.tsx.hbs +41 -0
  68. package/templates/portfolio/app/page.tsx.hbs +86 -0
  69. package/templates/portfolio/next.config.ts.hbs +7 -0
  70. package/templates/portfolio/postcss.config.mjs.hbs +14 -0
  71. package/templates/portfolio/proxy.ts.hbs +10 -0
  72. package/templates/portfolio/tsconfig.json.hbs +21 -0
  73. package/templates/saas/app/(auth)/sign-in/page.tsx.hbs +9 -0
  74. package/templates/saas/app/(auth)/sign-up/page.tsx.hbs +9 -0
  75. package/templates/saas/app/admin/billing/page.tsx.hbs +145 -0
  76. package/templates/saas/app/admin/page.tsx.hbs +106 -0
  77. package/templates/saas/app/admin/team/page.tsx.hbs +134 -0
  78. package/templates/saas/app/globals.css.hbs +87 -0
  79. package/templates/saas/app/layout.tsx.hbs +41 -0
  80. package/templates/saas/app/page.tsx.hbs +108 -0
  81. package/templates/saas/app/pricing/page.tsx.hbs +131 -0
  82. package/templates/saas/next.config.ts.hbs +7 -0
  83. package/templates/saas/postcss.config.mjs.hbs +14 -0
  84. package/templates/saas/proxy.ts.hbs +10 -0
  85. 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";
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 (recommended for first time)", hint: "Just auth + one homepage. Build whatever on top." },
334
- { value: "nextjs", label: "Next.js 16 \u2014 full kit", hint: "Dashboard \xB7 orgs \xB7 agents \xB7 MCP scaffolding" },
335
- { value: "react-vite", label: "React 19 + Vite 7", hint: "SPA \xB7 client-side routing" }
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, plain) {
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 = plain ? "plain" : "nextjs";
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: plain ? [] : ["forgot-password"],
610
+ authFeatures: isMinimal ? [] : ["forgot-password"],
603
611
  databaseChoice: "none",
604
612
  useTailwind: true,
605
- includeDashboard: !plain,
606
- includeGithatFolder: !plain && projectType === "frontend",
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(args.plain ? "Using plain defaults (--yes --plain)" : "Using defaults (--yes flag)");
614
- return getDefaults(args.initialName, args.publishableKey, args.typescript, args.fullstack, args.backendFramework, args.plain);
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 === "nextjs" || framework === "plain" ? options.fn(this) : options.inverse(this);
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 = ctx.framework === "nextjs" || ctx.framework === "plain";
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 === "plain") {
780
+ if (MINIMAL.has(ctx.framework)) {
739
781
  delete deps["@githat/ui"];
740
782
  }
741
- if (ctx.useTailwind || ctx.framework === "plain") {
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
- if (!isFullstack && (context.framework === "nextjs" || context.framework === "plain")) {
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, no orgs.").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) => {
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
- plain: opts.plain,
1675
+ template,
1622
1676
  fullstack: opts.fullstack,
1623
1677
  backendFramework: opts.backend
1624
1678
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-githat-app",
3
- "version": "1.0.14",
3
+ "version": "1.0.16",
4
4
  "description": "GitHat CLI — scaffold apps and manage the skills marketplace",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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,7 @@
1
+ import type { NextConfig } from 'next';
2
+
3
+ const nextConfig: NextConfig = {
4
+ output: 'standalone',
5
+ };
6
+
7
+ export default nextConfig;
@@ -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
+ }