create-githat-app 1.0.10 → 1.0.13

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 CHANGED
@@ -2,8 +2,8 @@ import { createRequire } from 'module'; const require = createRequire(import.met
2
2
 
3
3
  // src/cli.ts
4
4
  import { Command as Command7 } from "commander";
5
- import * as p11 from "@clack/prompts";
6
- import chalk9 from "chalk";
5
+ import * as p12 from "@clack/prompts";
6
+ import chalk10 from "chalk";
7
7
 
8
8
  // src/utils/ascii.ts
9
9
  import figlet from "figlet";
@@ -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.10";
14
+ var VERSION = "1.0.13";
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"];
@@ -21,7 +21,8 @@ var DEPS = {
21
21
  next: "^16.0.0",
22
22
  react: "^19.0.0",
23
23
  "react-dom": "^19.0.0",
24
- "@githat/nextjs": "^0.2.5"
24
+ "@githat/nextjs": "^0.5.0",
25
+ "@githat/ui": "^1.0.0"
25
26
  },
26
27
  devDependencies: {
27
28
  typescript: "^5.9.0",
@@ -35,7 +36,8 @@ var DEPS = {
35
36
  react: "^19.0.0",
36
37
  "react-dom": "^19.0.0",
37
38
  "react-router-dom": "^7.0.0",
38
- "@githat/nextjs": "^0.2.5"
39
+ "@githat/nextjs": "^0.5.0",
40
+ "@githat/ui": "^1.0.0"
39
41
  },
40
42
  devDependencies: {
41
43
  vite: "^7.0.0",
@@ -657,11 +659,11 @@ function answersToContext(answers) {
657
659
  }
658
660
 
659
661
  // src/scaffold/index.ts
660
- import fs3 from "fs-extra";
661
- import path3 from "path";
662
+ import fs4 from "fs-extra";
663
+ import path4 from "path";
662
664
  import { execSync as execSync3 } from "child_process";
663
- import * as p9 from "@clack/prompts";
664
- import chalk2 from "chalk";
665
+ import * as p10 from "@clack/prompts";
666
+ import chalk3 from "chalk";
665
667
 
666
668
  // src/utils/template-engine.ts
667
669
  import Handlebars from "handlebars";
@@ -809,27 +811,109 @@ function initGit(cwd) {
809
811
  }
810
812
  }
811
813
 
814
+ // src/utils/register-app.ts
815
+ import fs3 from "fs-extra";
816
+ import path3 from "path";
817
+ import os from "os";
818
+ import * as p9 from "@clack/prompts";
819
+ import chalk2 from "chalk";
820
+ var CREDENTIALS_PATH = path3.join(os.homedir(), ".githat", "credentials.json");
821
+ function readToken() {
822
+ if (!fs3.existsSync(CREDENTIALS_PATH)) {
823
+ return null;
824
+ }
825
+ try {
826
+ const creds = fs3.readJsonSync(CREDENTIALS_PATH);
827
+ return creds.token || null;
828
+ } catch {
829
+ return null;
830
+ }
831
+ }
832
+ async function registerApp(appName, projectRoot) {
833
+ const token = readToken();
834
+ if (!token) {
835
+ p9.log.warn(
836
+ chalk2.yellow(
837
+ `GitHat credentials not found at ${CREDENTIALS_PATH}.
838
+ Run ${chalk2.cyan("githat login")} then re-run scaffolding, or paste your publishable key
839
+ from ${chalk2.cyan("https://githat.io/dashboard/apps")} into .env.local manually.`
840
+ )
841
+ );
842
+ return null;
843
+ }
844
+ p9.log.step("Registering app on GitHat...");
845
+ let registeredApp;
846
+ try {
847
+ const response = await fetch(`${DEFAULT_API_URL}/apps`, {
848
+ method: "POST",
849
+ headers: {
850
+ "Content-Type": "application/json",
851
+ Authorization: `Bearer ${token}`
852
+ },
853
+ body: JSON.stringify({
854
+ name: appName,
855
+ redirect_uris: ["http://localhost:3000/callback"]
856
+ })
857
+ });
858
+ if (!response.ok) {
859
+ const body = await response.text().catch(() => "");
860
+ throw new Error(`HTTP ${response.status}: ${body}`);
861
+ }
862
+ registeredApp = await response.json();
863
+ } catch (err) {
864
+ p9.log.warn(
865
+ chalk2.yellow(
866
+ `Could not register app on GitHat: ${err.message}
867
+ The scaffold was written successfully. Once the API is available,
868
+ register manually at ${chalk2.cyan("https://githat.io/dashboard/apps")} and paste the
869
+ publishable key into ${chalk2.cyan(".env.local")}.`
870
+ )
871
+ );
872
+ return null;
873
+ }
874
+ const publishableKey = registeredApp.publishable_key;
875
+ const envLocalPath = path3.join(projectRoot, ".env.local");
876
+ try {
877
+ let envContent = fs3.existsSync(envLocalPath) ? fs3.readFileSync(envLocalPath, "utf-8") : "";
878
+ const keyLine = `NEXT_PUBLIC_GITHAT_PUBLISHABLE_KEY=${publishableKey}`;
879
+ if (envContent.includes("NEXT_PUBLIC_GITHAT_PUBLISHABLE_KEY=")) {
880
+ envContent = envContent.replace(
881
+ /NEXT_PUBLIC_GITHAT_PUBLISHABLE_KEY=.*/,
882
+ keyLine
883
+ );
884
+ } else {
885
+ envContent += (envContent.endsWith("\n") || envContent === "" ? "" : "\n") + keyLine + "\n";
886
+ }
887
+ fs3.ensureDirSync(path3.dirname(envLocalPath));
888
+ fs3.writeFileSync(envLocalPath, envContent, "utf-8");
889
+ } catch (err) {
890
+ p9.log.warn(chalk2.yellow(`Registered app but could not write .env.local: ${err.message}`));
891
+ }
892
+ p9.log.success(chalk2.green(`Registered "${appName}" on GitHat. Publishable key written to .env.local.`));
893
+ return publishableKey;
894
+ }
895
+
812
896
  // src/scaffold/index.ts
813
897
  async function scaffold(context, options) {
814
- const root = path3.resolve(process.cwd(), context.projectName);
815
- if (fs3.existsSync(root)) {
816
- p9.cancel(`Directory "${context.projectName}" already exists.`);
898
+ const root = path4.resolve(process.cwd(), context.projectName);
899
+ if (fs4.existsSync(root)) {
900
+ p10.cancel(`Directory "${context.projectName}" already exists.`);
817
901
  process.exit(1);
818
902
  }
819
903
  const isFullstack = context.projectType === "fullstack";
820
904
  await withSpinner("Creating project structure...", async () => {
821
- fs3.ensureDirSync(root);
905
+ fs4.ensureDirSync(root);
822
906
  const templatesRoot = getTemplatesRoot();
823
907
  if (isFullstack) {
824
908
  scaffoldFullstack(templatesRoot, root, context);
825
909
  } else {
826
- const frameworkDir = path3.join(templatesRoot, context.framework);
827
- if (!fs3.existsSync(frameworkDir)) {
910
+ const frameworkDir = path4.join(templatesRoot, context.framework);
911
+ if (!fs4.existsSync(frameworkDir)) {
828
912
  throw new Error(`Templates not found at ${frameworkDir}. This is a bug \u2014 please report it.`);
829
913
  }
830
914
  renderTemplateDirectory(frameworkDir, root, context);
831
- const baseDir = path3.join(templatesRoot, "base");
832
- if (fs3.existsSync(baseDir)) {
915
+ const baseDir = path4.join(templatesRoot, "base");
916
+ if (fs4.existsSync(baseDir)) {
833
917
  renderTemplateDirectory(baseDir, root, context);
834
918
  }
835
919
  }
@@ -840,6 +924,9 @@ async function scaffold(context, options) {
840
924
  writeJson(root, "package.json", pkg);
841
925
  }, "package.json generated");
842
926
  }
927
+ if (!isFullstack && context.framework === "nextjs") {
928
+ await registerApp(context.projectName, root);
929
+ }
843
930
  if (options.initGit) {
844
931
  const gitSpinner = createSpinner("Initializing git repository...");
845
932
  gitSpinner.start();
@@ -860,69 +947,69 @@ async function scaffold(context, options) {
860
947
  } catch (err) {
861
948
  const msg = err.message || "";
862
949
  if (msg.includes("TIMEOUT")) {
863
- p9.log.warn(`Install timed out. Run ${chalk2.cyan(installCmd)} manually.`);
950
+ p10.log.warn(`Install timed out. Run ${chalk3.cyan(installCmd)} manually.`);
864
951
  } else {
865
- p9.log.warn(`Could not auto-install. Run ${chalk2.cyan(installCmd)} manually.`);
952
+ p10.log.warn(`Could not auto-install. Run ${chalk3.cyan(installCmd)} manually.`);
866
953
  }
867
954
  }
868
955
  },
869
956
  "Dependencies installed"
870
957
  );
871
958
  }
872
- p9.outro("Setup complete!");
959
+ p10.outro("Setup complete!");
873
960
  displaySuccess(context.projectName, context.packageManager, context.framework, !!context.publishableKey, isFullstack);
874
961
  if (!options.skipPrompts) {
875
- const starPrompt = await p9.confirm({
962
+ const starPrompt = await p10.confirm({
876
963
  message: "Star GitHat on GitHub? (helps us grow!)",
877
964
  initialValue: false
878
965
  });
879
- if (!p9.isCancel(starPrompt) && starPrompt) {
966
+ if (!p10.isCancel(starPrompt) && starPrompt) {
880
967
  try {
881
968
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
882
969
  execSync3(`${cmd} "https://github.com/GitHat-IO/githat"`, { stdio: "ignore" });
883
970
  } catch {
884
- p9.log.info("Visit https://github.com/GitHat-IO/githat to star us!");
971
+ p10.log.info("Visit https://github.com/GitHat-IO/githat to star us!");
885
972
  }
886
973
  }
887
974
  }
888
975
  }
889
976
  function scaffoldFullstack(templatesRoot, root, context) {
890
- const fullstackDir = path3.join(templatesRoot, "fullstack");
891
- const rootDir = path3.join(fullstackDir, "root");
892
- if (fs3.existsSync(rootDir)) {
977
+ const fullstackDir = path4.join(templatesRoot, "fullstack");
978
+ const rootDir = path4.join(fullstackDir, "root");
979
+ if (fs4.existsSync(rootDir)) {
893
980
  renderTemplateDirectory(rootDir, root, context);
894
981
  }
895
- const appsDir = path3.join(root, "apps");
896
- fs3.ensureDirSync(appsDir);
897
- const webDir = path3.join(appsDir, "web");
898
- fs3.ensureDirSync(webDir);
899
- const webTemplateDir = path3.join(fullstackDir, `apps-web-${context.framework}`);
900
- if (fs3.existsSync(webTemplateDir)) {
982
+ const appsDir = path4.join(root, "apps");
983
+ fs4.ensureDirSync(appsDir);
984
+ const webDir = path4.join(appsDir, "web");
985
+ fs4.ensureDirSync(webDir);
986
+ const webTemplateDir = path4.join(fullstackDir, `apps-web-${context.framework}`);
987
+ if (fs4.existsSync(webTemplateDir)) {
901
988
  renderTemplateDirectory(webTemplateDir, webDir, context);
902
989
  } else {
903
990
  throw new Error(`Web app templates not found at ${webTemplateDir}. This is a bug \u2014 please report it.`);
904
991
  }
905
- const apiDir = path3.join(appsDir, "api");
906
- fs3.ensureDirSync(apiDir);
992
+ const apiDir = path4.join(appsDir, "api");
993
+ fs4.ensureDirSync(apiDir);
907
994
  const backendFramework = context.backendFramework || "hono";
908
- const apiTemplateDir = path3.join(fullstackDir, `apps-api-${backendFramework}`);
909
- if (fs3.existsSync(apiTemplateDir)) {
995
+ const apiTemplateDir = path4.join(fullstackDir, `apps-api-${backendFramework}`);
996
+ if (fs4.existsSync(apiTemplateDir)) {
910
997
  renderTemplateDirectory(apiTemplateDir, apiDir, context);
911
998
  } else {
912
999
  throw new Error(`API templates not found at ${apiTemplateDir}. This is a bug \u2014 please report it.`);
913
1000
  }
914
- const packagesDir = path3.join(root, "packages");
915
- fs3.ensureDirSync(packagesDir);
916
- fs3.writeFileSync(path3.join(packagesDir, ".gitkeep"), "");
1001
+ const packagesDir = path4.join(root, "packages");
1002
+ fs4.ensureDirSync(packagesDir);
1003
+ fs4.writeFileSync(path4.join(packagesDir, ".gitkeep"), "");
917
1004
  }
918
1005
 
919
1006
  // src/commands/skills/index.ts
920
1007
  import { Command as Command6 } from "commander";
921
- import chalk8 from "chalk";
1008
+ import chalk9 from "chalk";
922
1009
 
923
1010
  // src/commands/skills/search.ts
924
1011
  import { Command } from "commander";
925
- import chalk3 from "chalk";
1012
+ import chalk4 from "chalk";
926
1013
 
927
1014
  // src/commands/skills/api.ts
928
1015
  async function fetchApi(endpoint, options = {}) {
@@ -970,99 +1057,99 @@ async function getDownloadUrl(slug, version) {
970
1057
  // src/commands/skills/search.ts
971
1058
  function formatSkill(skill) {
972
1059
  const typeColors = {
973
- template: chalk3.blue,
974
- integration: chalk3.green,
975
- ui: chalk3.magenta,
976
- ai: chalk3.yellow,
977
- workflow: chalk3.cyan
1060
+ template: chalk4.blue,
1061
+ integration: chalk4.green,
1062
+ ui: chalk4.magenta,
1063
+ ai: chalk4.yellow,
1064
+ workflow: chalk4.cyan
978
1065
  };
979
- const typeColor = typeColors[skill.type] || chalk3.white;
1066
+ const typeColor = typeColors[skill.type] || chalk4.white;
980
1067
  return [
981
- `${chalk3.bold(skill.name)} ${chalk3.dim(`@${skill.latestVersion}`)}`,
1068
+ `${chalk4.bold(skill.name)} ${chalk4.dim(`@${skill.latestVersion}`)}`,
982
1069
  ` ${skill.description}`,
983
1070
  ` ${typeColor(skill.type)} \xB7 \u2B07 ${skill.downloads} \xB7 \u2B50 ${skill.stars} \xB7 by ${skill.authorName}`,
984
- ` ${chalk3.dim(`githat skills install ${skill.slug}`)}`
1071
+ ` ${chalk4.dim(`githat skills install ${skill.slug}`)}`
985
1072
  ].join("\n");
986
1073
  }
987
1074
  var searchCommand = new Command("search").description("Search skills by keyword").argument("<query>", "Search query").option("-t, --type <type>", "Filter by type (template, integration, ui, ai, workflow)").action(async (query, options) => {
988
1075
  try {
989
- console.log(chalk3.dim(`
1076
+ console.log(chalk4.dim(`
990
1077
  Searching for "${query}"...
991
1078
  `));
992
1079
  const result = await searchSkills(query, options.type);
993
1080
  if (result.skills.length === 0) {
994
- console.log(chalk3.yellow("No skills found matching your query."));
995
- console.log(chalk3.dim("\nTry a different search term or browse all skills:"));
996
- console.log(chalk3.dim(" githat skills list"));
1081
+ console.log(chalk4.yellow("No skills found matching your query."));
1082
+ console.log(chalk4.dim("\nTry a different search term or browse all skills:"));
1083
+ console.log(chalk4.dim(" githat skills list"));
997
1084
  return;
998
1085
  }
999
- console.log(chalk3.cyan(`Found ${result.skills.length} skill(s):
1086
+ console.log(chalk4.cyan(`Found ${result.skills.length} skill(s):
1000
1087
  `));
1001
1088
  for (const skill of result.skills) {
1002
1089
  console.log(formatSkill(skill));
1003
1090
  console.log("");
1004
1091
  }
1005
1092
  } catch (err) {
1006
- console.error(chalk3.red(`Error: ${err.message}`));
1093
+ console.error(chalk4.red(`Error: ${err.message}`));
1007
1094
  process.exit(1);
1008
1095
  }
1009
1096
  });
1010
1097
 
1011
1098
  // src/commands/skills/list.ts
1012
1099
  import { Command as Command2 } from "commander";
1013
- import chalk4 from "chalk";
1100
+ import chalk5 from "chalk";
1014
1101
  function formatSkillCompact(skill) {
1015
1102
  const typeColors = {
1016
- template: chalk4.blue,
1017
- integration: chalk4.green,
1018
- ui: chalk4.magenta,
1019
- ai: chalk4.yellow,
1020
- workflow: chalk4.cyan
1103
+ template: chalk5.blue,
1104
+ integration: chalk5.green,
1105
+ ui: chalk5.magenta,
1106
+ ai: chalk5.yellow,
1107
+ workflow: chalk5.cyan
1021
1108
  };
1022
- const typeColor = typeColors[skill.type] || chalk4.white;
1023
- const name = chalk4.bold(skill.name.padEnd(25));
1109
+ const typeColor = typeColors[skill.type] || chalk5.white;
1110
+ const name = chalk5.bold(skill.name.padEnd(25));
1024
1111
  const type = typeColor(skill.type.padEnd(12));
1025
1112
  const stats = `\u2B07 ${String(skill.downloads).padStart(5)} \u2B50 ${String(skill.stars).padStart(4)}`;
1026
1113
  const desc = skill.description.length > 40 ? skill.description.substring(0, 37) + "..." : skill.description;
1027
- return `${name} ${type} ${stats} ${chalk4.dim(desc)}`;
1114
+ return `${name} ${type} ${stats} ${chalk5.dim(desc)}`;
1028
1115
  }
1029
1116
  var listCommand = new Command2("list").description("List available skills").option("-t, --type <type>", "Filter by type (template, integration, ui, ai, workflow)").option("-l, --limit <n>", "Number of results (default: 25)", "25").action(async (options) => {
1030
1117
  try {
1031
1118
  const limit = parseInt(options.limit, 10);
1032
- console.log(chalk4.dim("\nFetching skills...\n"));
1119
+ console.log(chalk5.dim("\nFetching skills...\n"));
1033
1120
  const result = await listSkills({ type: options.type, limit });
1034
1121
  if (result.skills.length === 0) {
1035
- console.log(chalk4.yellow("No skills found."));
1122
+ console.log(chalk5.yellow("No skills found."));
1036
1123
  if (options.type) {
1037
- console.log(chalk4.dim(`
1124
+ console.log(chalk5.dim(`
1038
1125
  Try without the type filter:`));
1039
- console.log(chalk4.dim(" githat skills list"));
1126
+ console.log(chalk5.dim(" githat skills list"));
1040
1127
  }
1041
1128
  return;
1042
1129
  }
1043
1130
  const header = `${"NAME".padEnd(25)} ${"TYPE".padEnd(12)} ${"DOWNLOADS".padStart(10)} DESCRIPTION`;
1044
- console.log(chalk4.dim(header));
1045
- console.log(chalk4.dim("\u2500".repeat(80)));
1131
+ console.log(chalk5.dim(header));
1132
+ console.log(chalk5.dim("\u2500".repeat(80)));
1046
1133
  for (const skill of result.skills) {
1047
1134
  console.log(formatSkillCompact(skill));
1048
1135
  }
1049
- console.log(chalk4.dim("\u2500".repeat(80)));
1050
- console.log(chalk4.dim(`Showing ${result.skills.length} skill(s)`));
1136
+ console.log(chalk5.dim("\u2500".repeat(80)));
1137
+ console.log(chalk5.dim(`Showing ${result.skills.length} skill(s)`));
1051
1138
  if (result.nextCursor) {
1052
- console.log(chalk4.dim("\nMore results available. Use --limit to see more."));
1139
+ console.log(chalk5.dim("\nMore results available. Use --limit to see more."));
1053
1140
  }
1054
- console.log(chalk4.dim("\nTo install: githat skills install <name>"));
1141
+ console.log(chalk5.dim("\nTo install: githat skills install <name>"));
1055
1142
  } catch (err) {
1056
- console.error(chalk4.red(`Error: ${err.message}`));
1143
+ console.error(chalk5.red(`Error: ${err.message}`));
1057
1144
  process.exit(1);
1058
1145
  }
1059
1146
  });
1060
1147
 
1061
1148
  // src/commands/skills/install.ts
1062
1149
  import { Command as Command3 } from "commander";
1063
- import chalk5 from "chalk";
1064
- import * as fs4 from "fs";
1065
- import * as path4 from "path";
1150
+ import chalk6 from "chalk";
1151
+ import * as fs5 from "fs";
1152
+ import * as path5 from "path";
1066
1153
  import { pipeline } from "stream/promises";
1067
1154
  import { createWriteStream, mkdirSync } from "fs";
1068
1155
  import { Extract } from "unzipper";
@@ -1071,20 +1158,20 @@ async function downloadAndExtract(url, destDir) {
1071
1158
  if (!response.ok) {
1072
1159
  throw new Error(`Download failed: ${response.statusText}`);
1073
1160
  }
1074
- const tempZip = path4.join(destDir, ".skill-download.zip");
1161
+ const tempZip = path5.join(destDir, ".skill-download.zip");
1075
1162
  const fileStream = createWriteStream(tempZip);
1076
1163
  await pipeline(response.body, fileStream);
1077
1164
  await new Promise((resolve4, reject) => {
1078
- fs4.createReadStream(tempZip).pipe(Extract({ path: destDir })).on("close", resolve4).on("error", reject);
1165
+ fs5.createReadStream(tempZip).pipe(Extract({ path: destDir })).on("close", resolve4).on("error", reject);
1079
1166
  });
1080
- fs4.unlinkSync(tempZip);
1167
+ fs5.unlinkSync(tempZip);
1081
1168
  }
1082
1169
  function updateGithatLock(projectDir, skill) {
1083
- const lockPath = path4.join(projectDir, "githat.lock");
1170
+ const lockPath = path5.join(projectDir, "githat.lock");
1084
1171
  let lock = {};
1085
- if (fs4.existsSync(lockPath)) {
1172
+ if (fs5.existsSync(lockPath)) {
1086
1173
  try {
1087
- lock = JSON.parse(fs4.readFileSync(lockPath, "utf-8"));
1174
+ lock = JSON.parse(fs5.readFileSync(lockPath, "utf-8"));
1088
1175
  } catch {
1089
1176
  }
1090
1177
  }
@@ -1092,17 +1179,17 @@ function updateGithatLock(projectDir, skill) {
1092
1179
  version: skill.version,
1093
1180
  installedAt: (/* @__PURE__ */ new Date()).toISOString()
1094
1181
  };
1095
- fs4.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
1182
+ fs5.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
1096
1183
  }
1097
1184
  function updateEnvExample(projectDir, manifest) {
1098
1185
  if (!manifest.requires?.env?.length) return;
1099
- const envPath = path4.join(projectDir, ".env.local");
1100
- const envExamplePath = path4.join(projectDir, ".env.example");
1186
+ const envPath = path5.join(projectDir, ".env.local");
1187
+ const envExamplePath = path5.join(projectDir, ".env.example");
1101
1188
  let envContent = "";
1102
- if (fs4.existsSync(envPath)) {
1103
- envContent = fs4.readFileSync(envPath, "utf-8");
1104
- } else if (fs4.existsSync(envExamplePath)) {
1105
- envContent = fs4.readFileSync(envExamplePath, "utf-8");
1189
+ if (fs5.existsSync(envPath)) {
1190
+ envContent = fs5.readFileSync(envPath, "utf-8");
1191
+ } else if (fs5.existsSync(envExamplePath)) {
1192
+ envContent = fs5.readFileSync(envExamplePath, "utf-8");
1106
1193
  }
1107
1194
  const existingVars = new Set(
1108
1195
  envContent.split("\n").filter((line) => line.includes("=")).map((line) => line.split("=")[0].trim())
@@ -1118,10 +1205,10 @@ function updateEnvExample(projectDir, manifest) {
1118
1205
  # Added by skill install
1119
1206
  ${newVars.join("\n")}
1120
1207
  `;
1121
- if (fs4.existsSync(envPath)) {
1122
- fs4.appendFileSync(envPath, addition);
1208
+ if (fs5.existsSync(envPath)) {
1209
+ fs5.appendFileSync(envPath, addition);
1123
1210
  } else {
1124
- fs4.writeFileSync(envPath, `# Environment variables
1211
+ fs5.writeFileSync(envPath, `# Environment variables
1125
1212
  ${newVars.join("\n")}
1126
1213
  `);
1127
1214
  }
@@ -1129,112 +1216,112 @@ ${newVars.join("\n")}
1129
1216
  }
1130
1217
  var installCommand = new Command3("install").description("Install a skill to your project").argument("<slug>", "Skill slug (e.g., stripe-billing)").option("-v, --version <version>", "Specific version to install").option("-d, --dir <dir>", "Project directory (default: current directory)").action(async (slug, options) => {
1131
1218
  try {
1132
- const projectDir = options.dir ? path4.resolve(options.dir) : process.cwd();
1133
- const packageJsonPath = path4.join(projectDir, "package.json");
1134
- if (!fs4.existsSync(packageJsonPath)) {
1135
- console.error(chalk5.red("Error: No package.json found. Are you in a project directory?"));
1219
+ const projectDir = options.dir ? path5.resolve(options.dir) : process.cwd();
1220
+ const packageJsonPath = path5.join(projectDir, "package.json");
1221
+ if (!fs5.existsSync(packageJsonPath)) {
1222
+ console.error(chalk6.red("Error: No package.json found. Are you in a project directory?"));
1136
1223
  process.exit(1);
1137
1224
  }
1138
- console.log(chalk5.dim(`
1225
+ console.log(chalk6.dim(`
1139
1226
  Fetching skill info for "${slug}"...
1140
1227
  `));
1141
1228
  const skill = await getSkill(slug);
1142
- console.log(chalk5.cyan(`\u{1F4E6} ${skill.name}`));
1143
- console.log(chalk5.dim(` ${skill.description}`));
1144
- console.log(chalk5.dim(` Type: ${skill.type} \xB7 Author: ${skill.authorName}
1229
+ console.log(chalk6.cyan(`\u{1F4E6} ${skill.name}`));
1230
+ console.log(chalk6.dim(` ${skill.description}`));
1231
+ console.log(chalk6.dim(` Type: ${skill.type} \xB7 Author: ${skill.authorName}
1145
1232
  `));
1146
1233
  const download = await getDownloadUrl(slug, options.version);
1147
1234
  const version = download.version.version;
1148
- console.log(chalk5.dim(`Downloading ${skill.name}@${version}...`));
1149
- const skillDir = path4.join(projectDir, "githat", "skills", slug);
1235
+ console.log(chalk6.dim(`Downloading ${skill.name}@${version}...`));
1236
+ const skillDir = path5.join(projectDir, "githat", "skills", slug);
1150
1237
  mkdirSync(skillDir, { recursive: true });
1151
1238
  await downloadAndExtract(download.downloadUrl, skillDir);
1152
- console.log(chalk5.green(`\u2713 Downloaded to ${path4.relative(projectDir, skillDir)}`));
1153
- const manifestPath = path4.join(skillDir, "githat-skill.json");
1154
- if (fs4.existsSync(manifestPath)) {
1155
- const manifest = JSON.parse(fs4.readFileSync(manifestPath, "utf-8"));
1239
+ console.log(chalk6.green(`\u2713 Downloaded to ${path5.relative(projectDir, skillDir)}`));
1240
+ const manifestPath = path5.join(skillDir, "githat-skill.json");
1241
+ if (fs5.existsSync(manifestPath)) {
1242
+ const manifest = JSON.parse(fs5.readFileSync(manifestPath, "utf-8"));
1156
1243
  updateEnvExample(projectDir, manifest);
1157
1244
  if (manifest.requires?.env?.length) {
1158
- console.log(chalk5.yellow(`
1245
+ console.log(chalk6.yellow(`
1159
1246
  \u26A0 Required environment variables:`));
1160
1247
  for (const envVar of manifest.requires.env) {
1161
- console.log(chalk5.dim(` ${envVar}`));
1248
+ console.log(chalk6.dim(` ${envVar}`));
1162
1249
  }
1163
- console.log(chalk5.dim(`
1250
+ console.log(chalk6.dim(`
1164
1251
  Add these to your .env.local file`));
1165
1252
  }
1166
1253
  if (manifest.install?.dependencies) {
1167
1254
  const deps = Object.entries(manifest.install.dependencies).map(([name, ver]) => `${name}@${ver}`).join(" ");
1168
- console.log(chalk5.yellow(`
1255
+ console.log(chalk6.yellow(`
1169
1256
  \u26A0 Install npm dependencies:`));
1170
- console.log(chalk5.dim(` npm install ${deps}`));
1257
+ console.log(chalk6.dim(` npm install ${deps}`));
1171
1258
  }
1172
1259
  }
1173
1260
  updateGithatLock(projectDir, { slug, version });
1174
- console.log(chalk5.green(`
1261
+ console.log(chalk6.green(`
1175
1262
  \u2705 Successfully installed ${skill.name}@${version}
1176
1263
  `));
1177
- console.log(chalk5.dim("Next steps:"));
1178
- console.log(chalk5.dim(` 1. Check githat/skills/${slug}/README.md for usage`));
1179
- console.log(chalk5.dim(" 2. Add required environment variables to .env.local"));
1180
- console.log(chalk5.dim(" 3. Import and use the skill in your code"));
1264
+ console.log(chalk6.dim("Next steps:"));
1265
+ console.log(chalk6.dim(` 1. Check githat/skills/${slug}/README.md for usage`));
1266
+ console.log(chalk6.dim(" 2. Add required environment variables to .env.local"));
1267
+ console.log(chalk6.dim(" 3. Import and use the skill in your code"));
1181
1268
  } catch (err) {
1182
- console.error(chalk5.red(`Error: ${err.message}`));
1269
+ console.error(chalk6.red(`Error: ${err.message}`));
1183
1270
  process.exit(1);
1184
1271
  }
1185
1272
  });
1186
1273
 
1187
1274
  // src/commands/skills/installed.ts
1188
1275
  import { Command as Command4 } from "commander";
1189
- import chalk6 from "chalk";
1190
- import * as fs5 from "fs";
1191
- import * as path5 from "path";
1276
+ import chalk7 from "chalk";
1277
+ import * as fs6 from "fs";
1278
+ import * as path6 from "path";
1192
1279
  var installedCommand = new Command4("installed").alias("ls").description("List installed skills in current project").option("-d, --dir <dir>", "Project directory (default: current directory)").action(async (options) => {
1193
1280
  try {
1194
- const projectDir = options.dir ? path5.resolve(options.dir) : process.cwd();
1195
- const lockPath = path5.join(projectDir, "githat.lock");
1196
- if (!fs5.existsSync(lockPath)) {
1197
- console.log(chalk6.yellow("\nNo skills installed in this project."));
1198
- console.log(chalk6.dim("\nTo install a skill:"));
1199
- console.log(chalk6.dim(" githat skills install <slug>"));
1281
+ const projectDir = options.dir ? path6.resolve(options.dir) : process.cwd();
1282
+ const lockPath = path6.join(projectDir, "githat.lock");
1283
+ if (!fs6.existsSync(lockPath)) {
1284
+ console.log(chalk7.yellow("\nNo skills installed in this project."));
1285
+ console.log(chalk7.dim("\nTo install a skill:"));
1286
+ console.log(chalk7.dim(" githat skills install <slug>"));
1200
1287
  return;
1201
1288
  }
1202
1289
  let lock;
1203
1290
  try {
1204
- lock = JSON.parse(fs5.readFileSync(lockPath, "utf-8"));
1291
+ lock = JSON.parse(fs6.readFileSync(lockPath, "utf-8"));
1205
1292
  } catch {
1206
- console.error(chalk6.red("Error: Invalid githat.lock file"));
1293
+ console.error(chalk7.red("Error: Invalid githat.lock file"));
1207
1294
  process.exit(1);
1208
1295
  }
1209
1296
  const entries = Object.entries(lock);
1210
1297
  if (entries.length === 0) {
1211
- console.log(chalk6.yellow("\nNo skills installed in this project."));
1298
+ console.log(chalk7.yellow("\nNo skills installed in this project."));
1212
1299
  return;
1213
1300
  }
1214
- console.log(chalk6.cyan(`
1301
+ console.log(chalk7.cyan(`
1215
1302
  \u{1F4E6} Installed skills (${entries.length}):
1216
1303
  `));
1217
- console.log(chalk6.dim(`${"SKILL".padEnd(30)} ${"VERSION".padEnd(12)} INSTALLED`));
1218
- console.log(chalk6.dim("\u2500".repeat(60)));
1304
+ console.log(chalk7.dim(`${"SKILL".padEnd(30)} ${"VERSION".padEnd(12)} INSTALLED`));
1305
+ console.log(chalk7.dim("\u2500".repeat(60)));
1219
1306
  for (const [slug, entry] of entries) {
1220
1307
  const date = new Date(entry.installedAt).toLocaleDateString();
1221
- console.log(`${chalk6.bold(slug.padEnd(30))} ${entry.version.padEnd(12)} ${chalk6.dim(date)}`);
1308
+ console.log(`${chalk7.bold(slug.padEnd(30))} ${entry.version.padEnd(12)} ${chalk7.dim(date)}`);
1222
1309
  }
1223
- console.log(chalk6.dim("\u2500".repeat(60)));
1224
- console.log(chalk6.dim("\nTo update a skill:"));
1225
- console.log(chalk6.dim(" githat skills install <slug> --version <new-version>"));
1310
+ console.log(chalk7.dim("\u2500".repeat(60)));
1311
+ console.log(chalk7.dim("\nTo update a skill:"));
1312
+ console.log(chalk7.dim(" githat skills install <slug> --version <new-version>"));
1226
1313
  } catch (err) {
1227
- console.error(chalk6.red(`Error: ${err.message}`));
1314
+ console.error(chalk7.red(`Error: ${err.message}`));
1228
1315
  process.exit(1);
1229
1316
  }
1230
1317
  });
1231
1318
 
1232
1319
  // src/commands/skills/init.ts
1233
1320
  import { Command as Command5 } from "commander";
1234
- import chalk7 from "chalk";
1235
- import * as fs6 from "fs";
1236
- import * as path6 from "path";
1237
- import * as p10 from "@clack/prompts";
1321
+ import chalk8 from "chalk";
1322
+ import * as fs7 from "fs";
1323
+ import * as path7 from "path";
1324
+ import * as p11 from "@clack/prompts";
1238
1325
  var SKILL_TYPES = ["template", "integration", "ui", "ai", "workflow"];
1239
1326
  function generateReadme(manifest) {
1240
1327
  return `# ${manifest.name}
@@ -1366,23 +1453,23 @@ function toPascalCase(str) {
1366
1453
  var initCommand = new Command5("init").description("Initialize a new skill package").argument("<name>", "Skill name (slug format: lowercase-with-hyphens)").option("-t, --type <type>", "Skill type (template, integration, ui, ai, workflow)").option("-d, --dir <dir>", "Parent directory (default: current directory)").action(async (name, options) => {
1367
1454
  try {
1368
1455
  if (!/^[a-z][a-z0-9-]{1,62}[a-z0-9]$/.test(name)) {
1369
- console.error(chalk7.red("Error: Name must be lowercase alphanumeric with hyphens (2-64 chars, start with letter)"));
1456
+ console.error(chalk8.red("Error: Name must be lowercase alphanumeric with hyphens (2-64 chars, start with letter)"));
1370
1457
  process.exit(1);
1371
1458
  }
1372
- const parentDir = options.dir ? path6.resolve(options.dir) : process.cwd();
1373
- const skillDir = path6.join(parentDir, name);
1374
- if (fs6.existsSync(skillDir)) {
1375
- console.error(chalk7.red(`Error: Directory "${name}" already exists`));
1459
+ const parentDir = options.dir ? path7.resolve(options.dir) : process.cwd();
1460
+ const skillDir = path7.join(parentDir, name);
1461
+ if (fs7.existsSync(skillDir)) {
1462
+ console.error(chalk8.red(`Error: Directory "${name}" already exists`));
1376
1463
  process.exit(1);
1377
1464
  }
1378
- console.log(chalk7.cyan(`
1465
+ console.log(chalk8.cyan(`
1379
1466
  \u{1F4E6} Initializing skill: ${name}
1380
1467
  `));
1381
1468
  let type;
1382
1469
  if (options.type && SKILL_TYPES.includes(options.type)) {
1383
1470
  type = options.type;
1384
1471
  } else {
1385
- const result = await p10.select({
1472
+ const result = await p11.select({
1386
1473
  message: "What type of skill are you creating?",
1387
1474
  options: [
1388
1475
  { value: "integration", label: "Integration", hint: "Connect to external services (Stripe, SendGrid, etc.)" },
@@ -1392,19 +1479,19 @@ var initCommand = new Command5("init").description("Initialize a new skill packa
1392
1479
  { value: "workflow", label: "Workflow", hint: "Automation recipes" }
1393
1480
  ]
1394
1481
  });
1395
- if (p10.isCancel(result)) {
1396
- p10.cancel("Operation cancelled");
1482
+ if (p11.isCancel(result)) {
1483
+ p11.cancel("Operation cancelled");
1397
1484
  process.exit(0);
1398
1485
  }
1399
1486
  type = result;
1400
1487
  }
1401
- const description = await p10.text({
1488
+ const description = await p11.text({
1402
1489
  message: "Short description:",
1403
1490
  placeholder: `A ${type} skill for...`,
1404
1491
  validate: (v) => v.length < 10 ? "Description must be at least 10 characters" : void 0
1405
1492
  });
1406
- if (p10.isCancel(description)) {
1407
- p10.cancel("Operation cancelled");
1493
+ if (p11.isCancel(description)) {
1494
+ p11.cancel("Operation cancelled");
1408
1495
  process.exit(0);
1409
1496
  }
1410
1497
  const manifest = {
@@ -1429,22 +1516,22 @@ var initCommand = new Command5("init").description("Initialize a new skill packa
1429
1516
  },
1430
1517
  keywords: [type]
1431
1518
  };
1432
- fs6.mkdirSync(skillDir, { recursive: true });
1433
- fs6.mkdirSync(path6.join(skillDir, "src"), { recursive: true });
1434
- fs6.writeFileSync(
1435
- path6.join(skillDir, "githat-skill.json"),
1519
+ fs7.mkdirSync(skillDir, { recursive: true });
1520
+ fs7.mkdirSync(path7.join(skillDir, "src"), { recursive: true });
1521
+ fs7.writeFileSync(
1522
+ path7.join(skillDir, "githat-skill.json"),
1436
1523
  JSON.stringify(manifest, null, 2)
1437
1524
  );
1438
- fs6.writeFileSync(
1439
- path6.join(skillDir, "README.md"),
1525
+ fs7.writeFileSync(
1526
+ path7.join(skillDir, "README.md"),
1440
1527
  generateReadme(manifest)
1441
1528
  );
1442
- fs6.writeFileSync(
1443
- path6.join(skillDir, "src", "index.ts"),
1529
+ fs7.writeFileSync(
1530
+ path7.join(skillDir, "src", "index.ts"),
1444
1531
  generateIndexFile(manifest)
1445
1532
  );
1446
- fs6.writeFileSync(
1447
- path6.join(skillDir, ".gitignore"),
1533
+ fs7.writeFileSync(
1534
+ path7.join(skillDir, ".gitignore"),
1448
1535
  `node_modules/
1449
1536
  dist/
1450
1537
  .env
@@ -1452,21 +1539,21 @@ dist/
1452
1539
  *.log
1453
1540
  `
1454
1541
  );
1455
- console.log(chalk7.green(`
1542
+ console.log(chalk8.green(`
1456
1543
  \u2705 Created skill at ${skillDir}
1457
1544
  `));
1458
- console.log(chalk7.dim("Files created:"));
1459
- console.log(chalk7.dim(` githat-skill.json - Skill manifest`));
1460
- console.log(chalk7.dim(` README.md - Documentation`));
1461
- console.log(chalk7.dim(` src/index.ts - Main entry point`));
1462
- console.log(chalk7.dim(` .gitignore - Git ignore rules`));
1463
- console.log(chalk7.dim("\nNext steps:"));
1464
- console.log(chalk7.dim(` 1. cd ${name}`));
1465
- console.log(chalk7.dim(` 2. Edit githat-skill.json with your details`));
1466
- console.log(chalk7.dim(` 3. Implement your skill in src/index.ts`));
1467
- console.log(chalk7.dim(` 4. Publish: githat skills publish .`));
1545
+ console.log(chalk8.dim("Files created:"));
1546
+ console.log(chalk8.dim(` githat-skill.json - Skill manifest`));
1547
+ console.log(chalk8.dim(` README.md - Documentation`));
1548
+ console.log(chalk8.dim(` src/index.ts - Main entry point`));
1549
+ console.log(chalk8.dim(` .gitignore - Git ignore rules`));
1550
+ console.log(chalk8.dim("\nNext steps:"));
1551
+ console.log(chalk8.dim(` 1. cd ${name}`));
1552
+ console.log(chalk8.dim(` 2. Edit githat-skill.json with your details`));
1553
+ console.log(chalk8.dim(` 3. Implement your skill in src/index.ts`));
1554
+ console.log(chalk8.dim(` 4. Publish: githat skills publish .`));
1468
1555
  } catch (err) {
1469
- console.error(chalk7.red(`Error: ${err.message}`));
1556
+ console.error(chalk8.red(`Error: ${err.message}`));
1470
1557
  process.exit(1);
1471
1558
  }
1472
1559
  });
@@ -1474,7 +1561,7 @@ dist/
1474
1561
  // src/commands/skills/index.ts
1475
1562
  var skillsCommand = new Command6("skills").description("Manage GitHat skills marketplace").addCommand(searchCommand).addCommand(listCommand).addCommand(installCommand).addCommand(installedCommand).addCommand(initCommand);
1476
1563
  skillsCommand.action(() => {
1477
- console.log(chalk8.cyan("\n\u{1F4E6} GitHat Skills Marketplace\n"));
1564
+ console.log(chalk9.cyan("\n\u{1F4E6} GitHat Skills Marketplace\n"));
1478
1565
  console.log("Commands:");
1479
1566
  console.log(" search <query> Search skills by keyword");
1480
1567
  console.log(" list List skills (filterable by type)");
@@ -1497,7 +1584,7 @@ program.command("create [project-name]", { isDefault: true }).description("Scaff
1497
1584
  displayBanner();
1498
1585
  const typescript = opts.js ? false : opts.ts ? true : void 0;
1499
1586
  if (opts.yes && !projectName) {
1500
- p11.cancel(chalk9.red("Project name is required when using --yes flag"));
1587
+ p12.cancel(chalk10.red("Project name is required when using --yes flag"));
1501
1588
  process.exit(1);
1502
1589
  }
1503
1590
  const answers = await runPrompts({
@@ -1515,7 +1602,7 @@ program.command("create [project-name]", { isDefault: true }).description("Scaff
1515
1602
  skipPrompts: opts.yes
1516
1603
  });
1517
1604
  } catch (err) {
1518
- p11.cancel(chalk9.red(err.message || "Something went wrong."));
1605
+ p12.cancel(chalk10.red(err.message || "Something went wrong."));
1519
1606
  process.exit(1);
1520
1607
  }
1521
1608
  });