create-sitekick 0.2.1 → 0.2.3

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/index.js +93 -87
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1269,57 +1269,93 @@ function runInteractive(cmd, opts) {
1269
1269
  function isInstalled(cmd) {
1270
1270
  return run(`which ${cmd}`) !== null;
1271
1271
  }
1272
+ var scaffoldedDir = null;
1273
+ function abort(message = "Cancelled.") {
1274
+ if (scaffoldedDir && fs.existsSync(scaffoldedDir)) {
1275
+ fs.rmSync(scaffoldedDir, { recursive: true, force: true });
1276
+ }
1277
+ Ne(message);
1278
+ process.exit(0);
1279
+ }
1272
1280
  async function cancelOrContinue(message) {
1273
1281
  const result = await Re({ message, initialValue: true });
1274
- if (Ct(result)) {
1275
- Ne("Cancelled.");
1276
- process.exit(0);
1277
- }
1282
+ if (Ct(result))
1283
+ abort();
1278
1284
  return result;
1279
1285
  }
1280
1286
  var TOOLS = {
1281
1287
  gh: {
1282
1288
  name: "GitHub CLI",
1283
1289
  cmd: "gh",
1284
- installHint: "Install from https://cli.github.com or run: brew install gh"
1290
+ brewPkg: "gh"
1285
1291
  },
1286
1292
  vercel: {
1287
1293
  name: "Vercel CLI",
1288
1294
  cmd: "vercel",
1289
- installCmd: "bun add -g vercel"
1295
+ bunPkg: "vercel"
1290
1296
  },
1291
1297
  neonctl: {
1292
1298
  name: "Neon CLI",
1293
1299
  cmd: "neonctl",
1294
- installCmd: "bun add -g neonctl"
1300
+ bunPkg: "neonctl"
1295
1301
  },
1296
1302
  sanity: {
1297
1303
  name: "Sanity CLI",
1298
1304
  cmd: "sanity",
1299
- installCmd: "bun add -g sanity"
1305
+ bunPkg: "sanity"
1300
1306
  }
1301
1307
  };
1308
+ async function ensureBrew(s) {
1309
+ if (isInstalled("brew"))
1310
+ return true;
1311
+ const shouldInstall = await cancelOrContinue("Homebrew is needed to install some tools. Install it now?");
1312
+ if (!shouldInstall)
1313
+ return false;
1314
+ s.start("Installing Homebrew...");
1315
+ try {
1316
+ execSync('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', { stdio: "inherit" });
1317
+ } catch {
1318
+ s.stop("Failed to install Homebrew");
1319
+ return false;
1320
+ }
1321
+ const brewDirs = ["/opt/homebrew/bin", "/opt/homebrew/sbin", "/usr/local/bin", "/usr/local/sbin"];
1322
+ const currentPath = process.env.PATH || "";
1323
+ const newDirs = brewDirs.filter((d2) => !currentPath.includes(d2));
1324
+ if (newDirs.length > 0) {
1325
+ process.env.PATH = `${newDirs.join(":")}:${currentPath}`;
1326
+ }
1327
+ if (!isInstalled("brew")) {
1328
+ s.stop("Homebrew installed but not found on PATH. Restart your terminal and try again.");
1329
+ return false;
1330
+ }
1331
+ s.stop("Homebrew installed");
1332
+ return true;
1333
+ }
1302
1334
  async function ensureTool(key, s) {
1303
1335
  const tool = TOOLS[key];
1304
1336
  if (isInstalled(tool.cmd))
1305
1337
  return true;
1306
- if (tool.installCmd) {
1307
- const shouldInstall = await cancelOrContinue(`${tool.name} (${tool.cmd}) is not installed. Install it now?`);
1308
- if (!shouldInstall)
1309
- return false;
1310
- s.start(`Installing ${tool.name}...`);
1311
- const result = run(tool.installCmd);
1312
- if (result === null) {
1313
- s.stop(`Failed to install ${tool.name}`);
1338
+ const shouldInstall = await cancelOrContinue(`${tool.name} (${tool.cmd}) is not installed. Install it now?`);
1339
+ if (!shouldInstall)
1340
+ return false;
1341
+ let installCmd;
1342
+ if (tool.bunPkg) {
1343
+ installCmd = `bun add -g ${tool.bunPkg}`;
1344
+ } else if (tool.brewPkg) {
1345
+ if (!await ensureBrew(s))
1314
1346
  return false;
1315
- }
1316
- s.stop(`${tool.name} installed`);
1317
- return true;
1347
+ installCmd = `brew install ${tool.brewPkg}`;
1348
+ } else {
1349
+ return false;
1318
1350
  }
1319
- R2.warn(`${tool.name} (${import_picocolors3.default.cyan(tool.cmd)}) is not installed.
1320
- ${tool.installHint}`);
1321
- const ready = await cancelOrContinue(`Have you installed ${tool.cmd}? Continue?`);
1322
- return ready && isInstalled(tool.cmd);
1351
+ s.start(`Installing ${tool.name}...`);
1352
+ const result = run(installCmd);
1353
+ if (result === null) {
1354
+ s.stop(`Failed to install ${tool.name}`);
1355
+ return false;
1356
+ }
1357
+ s.stop(`${tool.name} installed`);
1358
+ return true;
1323
1359
  }
1324
1360
  async function ensureAuth(toolName, checkCmd, authCmd, s) {
1325
1361
  s.start(`Checking ${toolName} authentication...`);
@@ -1360,10 +1396,8 @@ async function selectGitHubOrg() {
1360
1396
  ...orgs.map((org) => ({ value: org, label: org }))
1361
1397
  ]
1362
1398
  });
1363
- if (Ct(selected)) {
1364
- Ne("Cancelled.");
1365
- process.exit(0);
1366
- }
1399
+ if (Ct(selected))
1400
+ abort();
1367
1401
  return selected === "__personal__" ? null : selected;
1368
1402
  }
1369
1403
  async function selectVercelTeam() {
@@ -1402,10 +1436,8 @@ async function selectVercelTeam() {
1402
1436
  }))
1403
1437
  ]
1404
1438
  });
1405
- if (Ct(selected)) {
1406
- Ne("Cancelled.");
1407
- process.exit(0);
1408
- }
1439
+ if (Ct(selected))
1440
+ abort();
1409
1441
  return selected === "__personal__" ? null : selected;
1410
1442
  }
1411
1443
  async function selectNeonOrg() {
@@ -1427,10 +1459,8 @@ async function selectNeonOrg() {
1427
1459
  }))
1428
1460
  ]
1429
1461
  });
1430
- if (Ct(selected)) {
1431
- Ne("Cancelled.");
1432
- process.exit(0);
1433
- }
1462
+ if (Ct(selected))
1463
+ abort();
1434
1464
  return selected === "__personal__" ? null : selected;
1435
1465
  } catch {
1436
1466
  return null;
@@ -1449,10 +1479,8 @@ async function setupGitHub(projectName, targetDir, s) {
1449
1479
  { value: "skip", label: "Skip GitHub setup" }
1450
1480
  ]
1451
1481
  });
1452
- if (Ct(existing)) {
1453
- Ne("Cancelled.");
1454
- process.exit(0);
1455
- }
1482
+ if (Ct(existing))
1483
+ abort();
1456
1484
  if (existing === "skip")
1457
1485
  return null;
1458
1486
  if (existing === "existing") {
@@ -1464,10 +1492,8 @@ async function setupGitHub(projectName, targetDir, s) {
1464
1492
  return "Repo URL is required";
1465
1493
  }
1466
1494
  });
1467
- if (Ct(repoUrl2)) {
1468
- Ne("Cancelled.");
1469
- process.exit(0);
1470
- }
1495
+ if (Ct(repoUrl2))
1496
+ abort();
1471
1497
  s.start("Linking to existing repo...");
1472
1498
  run(`git remote add origin ${repoUrl2}`, { cwd: targetDir });
1473
1499
  s.stop("Linked to existing repo");
@@ -1481,10 +1507,8 @@ async function setupGitHub(projectName, targetDir, s) {
1481
1507
  { value: "public", label: "Public" }
1482
1508
  ]
1483
1509
  });
1484
- if (Ct(visibility)) {
1485
- Ne("Cancelled.");
1486
- process.exit(0);
1487
- }
1510
+ if (Ct(visibility))
1511
+ abort();
1488
1512
  const repoFullName = ghOrg ? `${ghOrg}/${projectName}` : projectName;
1489
1513
  s.start(`Creating GitHub repo ${import_picocolors3.default.cyan(repoFullName)}...`);
1490
1514
  const result = run(`gh repo create ${repoFullName} --${visibility} --source . --remote origin`, { cwd: targetDir });
@@ -1509,10 +1533,8 @@ async function setupNeon(projectName, s) {
1509
1533
  { value: "skip", label: "Skip database setup" }
1510
1534
  ]
1511
1535
  });
1512
- if (Ct(existing)) {
1513
- Ne("Cancelled.");
1514
- process.exit(0);
1515
- }
1536
+ if (Ct(existing))
1537
+ abort();
1516
1538
  if (existing === "skip")
1517
1539
  return null;
1518
1540
  if (existing === "existing") {
@@ -1526,10 +1548,8 @@ async function setupNeon(projectName, s) {
1526
1548
  return "Must be a PostgreSQL connection string";
1527
1549
  }
1528
1550
  });
1529
- if (Ct(connStr)) {
1530
- Ne("Cancelled.");
1531
- process.exit(0);
1532
- }
1551
+ if (Ct(connStr))
1552
+ abort();
1533
1553
  return connStr;
1534
1554
  }
1535
1555
  const neonOrgId = await selectNeonOrg();
@@ -1583,10 +1603,8 @@ async function setupSanityProject(projectName, s) {
1583
1603
  { value: "skip", label: "Skip Sanity setup" }
1584
1604
  ]
1585
1605
  });
1586
- if (Ct(existing)) {
1587
- Ne("Cancelled.");
1588
- process.exit(0);
1589
- }
1606
+ if (Ct(existing))
1607
+ abort();
1590
1608
  if (existing === "skip")
1591
1609
  return null;
1592
1610
  if (existing === "existing") {
@@ -1598,19 +1616,15 @@ async function setupSanityProject(projectName, s) {
1598
1616
  return "Project ID is required";
1599
1617
  }
1600
1618
  });
1601
- if (Ct(projectId)) {
1602
- Ne("Cancelled.");
1603
- process.exit(0);
1604
- }
1619
+ if (Ct(projectId))
1620
+ abort();
1605
1621
  const dataset = await Ze({
1606
1622
  message: "Dataset name:",
1607
1623
  placeholder: "production",
1608
1624
  initialValue: "production"
1609
1625
  });
1610
- if (Ct(dataset)) {
1611
- Ne("Cancelled.");
1612
- process.exit(0);
1613
- }
1626
+ if (Ct(dataset))
1627
+ abort();
1614
1628
  return { projectId, dataset };
1615
1629
  }
1616
1630
  s.start(`Creating Sanity project ${import_picocolors3.default.cyan(projectName)}...`);
@@ -1647,10 +1661,8 @@ async function setupVercel(projectName, targetDir, repoUrl, s) {
1647
1661
  { value: "skip", label: "Skip Vercel setup" }
1648
1662
  ]
1649
1663
  });
1650
- if (Ct(existing)) {
1651
- Ne("Cancelled.");
1652
- process.exit(0);
1653
- }
1664
+ if (Ct(existing))
1665
+ abort();
1654
1666
  if (existing === "skip")
1655
1667
  return { url: null, scope: null };
1656
1668
  const vercelTeam = await selectVercelTeam();
@@ -1711,10 +1723,8 @@ async function askOpenAIKey() {
1711
1723
  { value: "skip", label: "Skip — set up later" }
1712
1724
  ]
1713
1725
  });
1714
- if (Ct(setup)) {
1715
- Ne("Cancelled.");
1716
- process.exit(0);
1717
- }
1726
+ if (Ct(setup))
1727
+ abort();
1718
1728
  if (setup === "skip")
1719
1729
  return null;
1720
1730
  const key = await Ze({
@@ -1727,10 +1737,8 @@ async function askOpenAIKey() {
1727
1737
  return "OpenAI keys start with sk-";
1728
1738
  }
1729
1739
  });
1730
- if (Ct(key)) {
1731
- Ne("Cancelled.");
1732
- process.exit(0);
1733
- }
1740
+ if (Ct(key))
1741
+ abort();
1734
1742
  return key;
1735
1743
  }
1736
1744
  function configureTemplate(targetDir, cms, projectName) {
@@ -1862,10 +1870,8 @@ async function main() {
1862
1870
  return "Use lowercase letters, numbers, and hyphens only";
1863
1871
  }
1864
1872
  });
1865
- if (Ct(projectName)) {
1866
- Ne("Cancelled.");
1867
- process.exit(0);
1868
- }
1873
+ if (Ct(projectName))
1874
+ abort();
1869
1875
  const cms = await Je({
1870
1876
  message: "Which CMS do you want to use?",
1871
1877
  options: [
@@ -1881,19 +1887,19 @@ async function main() {
1881
1887
  }
1882
1888
  ]
1883
1889
  });
1884
- if (Ct(cms)) {
1885
- Ne("Cancelled.");
1886
- process.exit(0);
1887
- }
1890
+ if (Ct(cms))
1891
+ abort();
1888
1892
  const targetDir = path.resolve(process.cwd(), projectName);
1889
1893
  if (fs.existsSync(targetDir)) {
1890
1894
  Ne(`Directory ${import_picocolors3.default.cyan(projectName)} already exists.`);
1891
1895
  process.exit(1);
1892
1896
  }
1893
1897
  const s = bt2();
1898
+ await ensureBrew(s);
1894
1899
  s.start("Cloning sitekick-starter...");
1895
1900
  execSync(`git clone --depth 1 https://github.com/sitekickcodes/sitekick-starter.git ${targetDir}`, { stdio: "pipe" });
1896
1901
  fs.rmSync(path.join(targetDir, ".git"), { recursive: true, force: true });
1902
+ scaffoldedDir = targetDir;
1897
1903
  s.stop("Cloned template");
1898
1904
  s.start(`Configuring for ${cms === "payload" ? "Payload CMS" : "Sanity"}...`);
1899
1905
  configureTemplate(targetDir, cms, projectName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-sitekick",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Scaffold a new Sitekick project with your choice of CMS",
5
5
  "type": "module",
6
6
  "bin": {