create-githat-app 1.1.0 → 1.2.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 (2) hide show
  1. package/dist/cli.js +104 -123
  2. package/package.json +1 -1
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.1.0";
14
+ var VERSION = "1.2.0";
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"];
@@ -77,35 +77,66 @@ var DEPS = {
77
77
  };
78
78
 
79
79
  // src/utils/ascii.ts
80
- var githatGradient = gradient([...BRAND_COLORS]);
80
+ var brand = gradient([...BRAND_COLORS]);
81
+ var violet = chalk.hex("#a78bfa");
82
+ var dim = chalk.dim;
83
+ function visibleLength(str) {
84
+ return str.replace(/\u001b\[.*?m/g, "").length;
85
+ }
86
+ function drawBox(lines) {
87
+ const W = 54;
88
+ const hr = "\u2500".repeat(W);
89
+ console.log(dim(` \u256D${hr}\u256E`));
90
+ console.log(dim(` \u2502${" ".repeat(W)}\u2502`));
91
+ for (const line of lines) {
92
+ const pad = W - 2 - visibleLength(line);
93
+ console.log(dim(" \u2502") + ` ${line}${" ".repeat(Math.max(0, pad))}` + dim("\u2502"));
94
+ }
95
+ console.log(dim(` \u2502${" ".repeat(W)}\u2502`));
96
+ console.log(dim(` \u2570${hr}\u256F`));
97
+ }
81
98
  function displayBanner() {
82
99
  const ascii = figlet.textSync("GitHat", {
83
- font: "Slant",
100
+ font: "ANSI Shadow",
84
101
  horizontalLayout: "default"
85
102
  });
86
103
  console.log("");
87
- console.log(githatGradient(ascii));
88
- console.log(chalk.dim(" Identity for humans, agents, and MCP servers"));
89
- console.log(chalk.dim(` v${VERSION} | githat.io`));
104
+ console.log(brand(ascii));
105
+ drawBox([
106
+ `${violet("\u2726")} Create a new GitHat app`,
107
+ "",
108
+ dim("The developer platform"),
109
+ dim("for humans, agents & MCP servers"),
110
+ "",
111
+ dim(`v${VERSION} \xB7 githat.io`)
112
+ ]);
113
+ console.log("");
114
+ }
115
+ function sectionHeader(title) {
116
+ const line = "\u2500".repeat(Math.max(1, 38 - title.length));
117
+ console.log("");
118
+ console.log(dim(` \u2500\u2500\u2500 ${title} ${line}`));
90
119
  console.log("");
91
120
  }
92
121
  function displaySuccess(projectName, packageManager, framework) {
93
122
  const devCmd = packageManager === "npm" ? "npm run dev" : `${packageManager} dev`;
94
123
  const port = framework === "react-vite" ? "5173" : "3000";
95
124
  console.log("");
96
- console.log(githatGradient(" \u2726 Your GitHat app is ready!"));
97
- console.log("");
98
- console.log(` ${chalk.cyan("cd")} ${projectName}`);
99
- console.log(` ${chalk.cyan(devCmd)}`);
100
- console.log("");
101
- console.log(chalk.dim(` \u2192 http://localhost:${port}`));
102
- console.log("");
103
- console.log(chalk.dim(" Routes:"));
104
- console.log(chalk.dim(" /sign-in Sign in"));
105
- console.log(chalk.dim(" /sign-up Create account"));
106
- console.log(chalk.dim(" /dashboard Protected dashboard"));
107
- console.log("");
108
- console.log(chalk.dim(" Docs: https://githat.io/docs/sdk"));
125
+ drawBox([
126
+ `${violet("\u2726")} Your GitHat app is ready!`,
127
+ "",
128
+ `${violet("$")} cd ${projectName}`,
129
+ `${violet("$")} ${devCmd}`,
130
+ "",
131
+ dim(`\u2192 http://localhost:${port}`),
132
+ "",
133
+ chalk.bold("Routes"),
134
+ `${violet("/sign-in")} Sign in`,
135
+ `${violet("/sign-up")} Create account`,
136
+ `${violet("/dashboard")} Protected dashboard`,
137
+ "",
138
+ dim("Docs \u2192 https://githat.io/docs/sdk")
139
+ ]);
109
140
  console.log("");
110
141
  }
111
142
 
@@ -132,15 +163,6 @@ function validatePublishableKey(key) {
132
163
  }
133
164
  return void 0;
134
165
  }
135
- function validateApiUrl(url) {
136
- if (!url) return "API URL is required";
137
- try {
138
- new URL(url);
139
- return void 0;
140
- } catch {
141
- return "Must be a valid URL";
142
- }
143
- }
144
166
 
145
167
  // src/prompts/project.ts
146
168
  async function promptProject(initialName) {
@@ -153,14 +175,9 @@ async function promptProject(initialName) {
153
175
  validate: validateProjectName
154
176
  }),
155
177
  businessName: () => p.text({
156
- message: "Business or app display name",
178
+ message: "Display name",
157
179
  placeholder: "Acme Corp",
158
180
  validate: (v) => !v ? "Display name is required" : void 0
159
- }),
160
- description: () => p.text({
161
- message: "One-line description",
162
- placeholder: "A platform for managing identity across humans and AI",
163
- initialValue: ""
164
181
  })
165
182
  },
166
183
  {
@@ -173,7 +190,7 @@ async function promptProject(initialName) {
173
190
  return {
174
191
  projectName: answers.projectName,
175
192
  businessName: answers.businessName,
176
- description: answers.description || `${answers.businessName} \u2014 Built with GitHat identity`
193
+ description: `${answers.businessName} \u2014 Built with GitHat`
177
194
  };
178
195
  }
179
196
 
@@ -181,7 +198,6 @@ async function promptProject(initialName) {
181
198
  import * as p2 from "@clack/prompts";
182
199
 
183
200
  // src/utils/package-manager.ts
184
- import { execSync } from "child_process";
185
201
  function detectPackageManager() {
186
202
  const userAgent = process.env.npm_config_user_agent || "";
187
203
  if (userAgent.startsWith("pnpm")) return "pnpm";
@@ -189,14 +205,6 @@ function detectPackageManager() {
189
205
  if (userAgent.startsWith("bun")) return "bun";
190
206
  return "npm";
191
207
  }
192
- function isAvailable(pm) {
193
- try {
194
- execSync(`${pm} --version`, { stdio: "ignore" });
195
- return true;
196
- } catch {
197
- return false;
198
- }
199
- }
200
208
  function getInstallCommand(pm) {
201
209
  const cmds = {
202
210
  npm: "npm install",
@@ -209,14 +217,14 @@ function getInstallCommand(pm) {
209
217
 
210
218
  // src/prompts/framework.ts
211
219
  async function promptFramework(typescriptOverride) {
212
- const detected = detectPackageManager();
220
+ const packageManager = detectPackageManager();
213
221
  const answers = await p2.group(
214
222
  {
215
223
  framework: () => p2.select({
216
224
  message: "Framework",
217
225
  options: [
218
- { value: "nextjs", label: "Next.js 16", hint: "App Router, SSR, middleware auth" },
219
- { value: "react-vite", label: "React 19 + Vite 7", hint: "SPA, client-side routing" }
226
+ { value: "nextjs", label: "Next.js 16", hint: "App Router \xB7 SSR \xB7 middleware auth" },
227
+ { value: "react-vite", label: "React 19 + Vite 7", hint: "SPA \xB7 client-side routing" }
220
228
  ]
221
229
  }),
222
230
  typescript: () => typescriptOverride !== void 0 ? Promise.resolve(typescriptOverride) : p2.select({
@@ -225,15 +233,6 @@ async function promptFramework(typescriptOverride) {
225
233
  { value: true, label: "TypeScript", hint: "recommended" },
226
234
  { value: false, label: "JavaScript" }
227
235
  ]
228
- }),
229
- packageManager: () => p2.select({
230
- message: "Package manager",
231
- initialValue: detected,
232
- options: ["npm", "pnpm", "yarn", "bun"].filter((pm) => pm === detected || isAvailable(pm)).map((pm) => ({
233
- value: pm,
234
- label: pm,
235
- hint: pm === detected ? "detected" : void 0
236
- }))
237
236
  })
238
237
  },
239
238
  {
@@ -246,17 +245,17 @@ async function promptFramework(typescriptOverride) {
246
245
  return {
247
246
  framework: answers.framework,
248
247
  typescript: answers.typescript,
249
- packageManager: answers.packageManager
248
+ packageManager
250
249
  };
251
250
  }
252
251
 
253
252
  // src/prompts/githat.ts
254
- import { execSync as execSync2 } from "child_process";
253
+ import { execSync } from "child_process";
255
254
  import * as p3 from "@clack/prompts";
256
255
  function openBrowser(url) {
257
256
  try {
258
257
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
259
- execSync2(`${cmd} "${url}"`, { stdio: "ignore" });
258
+ execSync(`${cmd} "${url}"`, { stdio: "ignore" });
260
259
  } catch {
261
260
  }
262
261
  }
@@ -268,7 +267,7 @@ async function promptGitHat(existingKey) {
268
267
  options: [
269
268
  { value: "browser", label: "Sign in with browser", hint: "opens githat.io \u2014 recommended" },
270
269
  { value: "paste", label: "I have a key", hint: "paste your pk_live_... key" },
271
- { value: "skip", label: "Skip for now", hint: "add key to .env.local later" }
270
+ { value: "skip", label: "Skip for now", hint: "add key to .env later" }
272
271
  ]
273
272
  });
274
273
  if (p3.isCancel(connectChoice)) {
@@ -277,8 +276,8 @@ async function promptGitHat(existingKey) {
277
276
  }
278
277
  if (connectChoice === "browser") {
279
278
  p3.log.step("Opening githat.io in your browser...");
280
- openBrowser(`https://githat.io/sign-up`);
281
- p3.log.info("Sign up (or sign in), then go to Dashboard \u2192 Apps to copy your publishable key.");
279
+ openBrowser("https://githat.io/sign-up");
280
+ p3.log.info("Sign up (or sign in), then go to Dashboard \u2192 Apps to copy your key.");
282
281
  const pastedKey = await p3.text({
283
282
  message: "Paste your publishable key",
284
283
  placeholder: "pk_live_...",
@@ -302,38 +301,26 @@ async function promptGitHat(existingKey) {
302
301
  publishableKey = pastedKey || "";
303
302
  }
304
303
  }
305
- const answers = await p3.group(
306
- {
307
- apiUrl: () => p3.text({
308
- message: "GitHat API URL",
309
- placeholder: DEFAULT_API_URL,
310
- initialValue: DEFAULT_API_URL,
311
- validate: validateApiUrl
312
- }),
313
- authFeatures: () => p3.multiselect({
314
- message: "Auth features",
315
- options: [
316
- { value: "forgot-password", label: "Forgot password / Reset password", hint: "recommended" },
317
- { value: "email-verification", label: "Email verification", hint: "recommended" },
318
- { value: "org-management", label: "Organization management", hint: "teams, invites, roles" },
319
- { value: "mcp-servers", label: "MCP server registration", hint: "tool verification" },
320
- { value: "ai-agents", label: "AI agent wallet auth", hint: "Ethereum signatures" }
321
- ],
322
- initialValues: ["forgot-password", "email-verification"],
323
- required: false
324
- })
325
- },
326
- {
327
- onCancel: () => {
328
- p3.cancel("Setup cancelled.");
329
- process.exit(0);
330
- }
331
- }
332
- );
304
+ const authFeatures = await p3.multiselect({
305
+ message: "Auth features",
306
+ options: [
307
+ { value: "forgot-password", label: "Forgot password", hint: "reset via email" },
308
+ { value: "email-verification", label: "Email verification" },
309
+ { value: "org-management", label: "Organizations", hint: "teams & roles" },
310
+ { value: "mcp-servers", label: "MCP servers", hint: "Model Context Protocol" },
311
+ { value: "ai-agents", label: "AI agents", hint: "wallet-based identity" }
312
+ ],
313
+ initialValues: ["forgot-password", "email-verification"],
314
+ required: false
315
+ });
316
+ if (p3.isCancel(authFeatures)) {
317
+ p3.cancel("Setup cancelled.");
318
+ process.exit(0);
319
+ }
333
320
  return {
334
321
  publishableKey,
335
- apiUrl: answers.apiUrl || DEFAULT_API_URL,
336
- authFeatures: answers.authFeatures || []
322
+ apiUrl: DEFAULT_API_URL,
323
+ authFeatures: authFeatures || []
337
324
  };
338
325
  }
339
326
 
@@ -345,22 +332,15 @@ async function promptFeatures() {
345
332
  databaseChoice: () => p4.select({
346
333
  message: "Database",
347
334
  options: [
348
- { value: "none", label: "None \u2014 API only", hint: "use GitHat backend directly" },
335
+ { value: "none", label: "None", hint: "use GitHat backend directly" },
349
336
  { value: "prisma-postgres", label: "Prisma + PostgreSQL" },
350
337
  { value: "prisma-mysql", label: "Prisma + MySQL" },
351
338
  { value: "drizzle-postgres", label: "Drizzle + PostgreSQL" },
352
339
  { value: "drizzle-sqlite", label: "Drizzle + SQLite" }
353
340
  ]
354
341
  }),
355
- useTailwind: () => p4.confirm({ message: "Include Tailwind CSS?", initialValue: true }),
356
- includeDashboard: () => p4.confirm({
357
- message: "Include full dashboard?",
358
- initialValue: true
359
- }),
360
- includeGithatFolder: () => p4.confirm({
361
- message: "Include githat/ platform folder?",
362
- initialValue: true
363
- })
342
+ useTailwind: () => p4.confirm({ message: "Tailwind CSS?", initialValue: true }),
343
+ includeDashboard: () => p4.confirm({ message: "Include dashboard?", initialValue: true })
364
344
  },
365
345
  {
366
346
  onCancel: () => {
@@ -373,38 +353,39 @@ async function promptFeatures() {
373
353
  databaseChoice: answers.databaseChoice,
374
354
  useTailwind: answers.useTailwind,
375
355
  includeDashboard: answers.includeDashboard,
376
- includeGithatFolder: answers.includeGithatFolder
356
+ includeGithatFolder: true
377
357
  };
378
358
  }
379
359
 
380
360
  // src/prompts/finalize.ts
381
361
  import * as p5 from "@clack/prompts";
382
362
  async function promptFinalize() {
383
- const answers = await p5.group(
384
- {
385
- initGit: () => p5.confirm({ message: "Initialize git repository?", initialValue: true }),
386
- installDeps: () => p5.confirm({ message: "Install dependencies now?", initialValue: true })
387
- },
388
- {
389
- onCancel: () => {
390
- p5.cancel("Setup cancelled.");
391
- process.exit(0);
392
- }
393
- }
394
- );
363
+ const installDeps = await p5.confirm({
364
+ message: "Install dependencies?",
365
+ initialValue: true
366
+ });
367
+ if (p5.isCancel(installDeps)) {
368
+ p5.cancel("Setup cancelled.");
369
+ process.exit(0);
370
+ }
395
371
  return {
396
- initGit: answers.initGit,
397
- installDeps: answers.installDeps
372
+ initGit: true,
373
+ installDeps
398
374
  };
399
375
  }
400
376
 
401
377
  // src/prompts/index.ts
402
378
  async function runPrompts(args) {
403
379
  p6.intro("Let\u2019s set up your GitHat app");
380
+ sectionHeader("Project");
404
381
  const project = await promptProject(args.initialName);
382
+ sectionHeader("Stack");
405
383
  const framework = await promptFramework(args.typescript);
384
+ sectionHeader("Connect");
406
385
  const githat = await promptGitHat(args.publishableKey);
386
+ sectionHeader("Features");
407
387
  const features = await promptFeatures();
388
+ sectionHeader("Finish");
408
389
  const finalize = await promptFinalize();
409
390
  return { ...project, ...framework, ...githat, ...features, ...finalize };
410
391
  }
@@ -436,7 +417,7 @@ function answersToContext(answers) {
436
417
  // src/scaffold/index.ts
437
418
  import fs3 from "fs-extra";
438
419
  import path3 from "path";
439
- import { execSync as execSync4 } from "child_process";
420
+ import { execSync as execSync3 } from "child_process";
440
421
  import * as p7 from "@clack/prompts";
441
422
  import chalk2 from "chalk";
442
423
 
@@ -571,12 +552,12 @@ async function withSpinner(text3, fn, successText) {
571
552
  }
572
553
 
573
554
  // src/utils/git.ts
574
- import { execSync as execSync3 } from "child_process";
555
+ import { execSync as execSync2 } from "child_process";
575
556
  function initGit(cwd) {
576
557
  try {
577
- execSync3("git init", { cwd, stdio: "ignore" });
578
- execSync3("git add -A", { cwd, stdio: "ignore" });
579
- execSync3('git commit -m "Initial commit from create-githat-app"', {
558
+ execSync2("git init", { cwd, stdio: "ignore" });
559
+ execSync2("git add -A", { cwd, stdio: "ignore" });
560
+ execSync2('git commit -m "Initial commit from create-githat-app"', {
580
561
  cwd,
581
562
  stdio: "ignore"
582
563
  });
@@ -625,7 +606,7 @@ async function scaffold(context, options) {
625
606
  `Installing dependencies with ${context.packageManager}...`,
626
607
  async () => {
627
608
  try {
628
- execSync4(installCmd, { cwd: root, stdio: "ignore", timeout: 12e4 });
609
+ execSync3(installCmd, { cwd: root, stdio: "ignore", timeout: 12e4 });
629
610
  } catch (err) {
630
611
  const msg = err.message || "";
631
612
  if (msg.includes("TIMEOUT")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-githat-app",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Scaffold enterprise-grade apps with GitHat identity — for humans, AI agents, and MCP servers",
5
5
  "type": "module",
6
6
  "bin": {