@appsbyme/create-basekit 1.0.4 → 1.0.5

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.
@@ -5232,19 +5232,7 @@ function createSpinner(text) {
5232
5232
  init_cjs_shims();
5233
5233
  var import_fs2 = __toESM(require("fs"), 1);
5234
5234
  var import_path = __toESM(require("path"), 1);
5235
- var DJANGO_BASE_PYPI_REQUIREMENT = "appsbyme-basekit[cli]==1.0.0";
5236
- function getWebKitRootFromPackage() {
5237
- let dir = import_path.default.resolve(__dirname);
5238
- for (let i = 0; i < 6; i += 1) {
5239
- if (import_fs2.default.existsSync(import_path.default.join(dir, "packages", "utils", "package.json"))) {
5240
- return dir;
5241
- }
5242
- const parent = import_path.default.dirname(dir);
5243
- if (parent === dir) break;
5244
- dir = parent;
5245
- }
5246
- return import_path.default.resolve(__dirname, "../../..");
5247
- }
5235
+ var DJANGO_BASE_PYPI_REQUIREMENT = "appsbyme-basekit[cli]>=1.0.0";
5248
5236
  function djangoBasePipInstallArg(spec) {
5249
5237
  if (spec.kind === "pypi") {
5250
5238
  return spec.pipSpec;
@@ -5260,7 +5248,7 @@ function filePipSpec(absoluteDir) {
5260
5248
  const withSlash = normalized.startsWith("/") ? normalized : `/${normalized}`;
5261
5249
  return `file://${withSlash}`;
5262
5250
  }
5263
- function resolveDjangoBaseInstallSpec(opts) {
5251
+ function resolveDjangoBaseInstallSpec(opts = {}) {
5264
5252
  const env = opts.env ?? process.env;
5265
5253
  const envPath = env.BASEKIT_DJANGO_BASE?.trim();
5266
5254
  if (envPath) {
@@ -5273,24 +5261,6 @@ function resolveDjangoBaseInstallSpec(opts) {
5273
5261
  };
5274
5262
  }
5275
5263
  }
5276
- const besideProject = import_path.default.resolve(opts.projectRoot, "..", "basekit");
5277
- if (isUsableCheckout(besideProject)) {
5278
- return {
5279
- kind: "file",
5280
- pipSpec: filePipSpec(besideProject),
5281
- label: `sibling beside project (${besideProject})`
5282
- };
5283
- }
5284
- if (opts.webKitRoot) {
5285
- const besideWebKit = import_path.default.resolve(opts.webKitRoot, "..", "basekit");
5286
- if (isUsableCheckout(besideWebKit)) {
5287
- return {
5288
- kind: "file",
5289
- pipSpec: filePipSpec(besideWebKit),
5290
- label: `sibling beside basekit-web (${besideWebKit})`
5291
- };
5292
- }
5293
- }
5294
5264
  return {
5295
5265
  kind: "pypi",
5296
5266
  pipSpec: DJANGO_BASE_PYPI_REQUIREMENT,
@@ -5315,10 +5285,7 @@ async function scaffoldBackend(opts) {
5315
5285
  }
5316
5286
  venvSpinner.succeed("Virtual environment created at backend/.venv");
5317
5287
  const pip = venvBin(venvDir, "pip");
5318
- const djangoBase = resolveDjangoBaseInstallSpec({
5319
- projectRoot,
5320
- webKitRoot: getWebKitRootFromPackage()
5321
- });
5288
+ const djangoBase = resolveDjangoBaseInstallSpec();
5322
5289
  const pipArg = djangoBasePipInstallArg(djangoBase);
5323
5290
  const installSpinner = createSpinner(`Installing appsbyme-basekit[cli] from ${djangoBase.label}\u2026`);
5324
5291
  const installResult = await execAsync(
@@ -5427,19 +5394,46 @@ function safeUnlink(absPath) {
5427
5394
  // src/commands/app/frontend.ts
5428
5395
  init_cjs_shims();
5429
5396
  var import_path8 = __toESM(require("path"), 1);
5430
- var import_fs8 = __toESM(require("fs"), 1);
5397
+ var import_fs9 = __toESM(require("fs"), 1);
5431
5398
 
5432
5399
  // src/commands/web/index.ts
5433
5400
  init_cjs_shims();
5434
- var import_path5 = __toESM(require("path"), 1);
5435
- var import_fs6 = __toESM(require("fs"), 1);
5401
+ var import_path6 = __toESM(require("path"), 1);
5402
+ var import_fs7 = __toESM(require("fs"), 1);
5436
5403
  var import_prompts = __toESM(require_prompts3(), 1);
5437
5404
 
5438
5405
  // src/commands/web/scaffold.ts
5439
5406
  init_cjs_shims();
5440
- var import_fs5 = __toESM(require("fs"), 1);
5441
- var import_path4 = __toESM(require("path"), 1);
5407
+ var import_fs6 = __toESM(require("fs"), 1);
5408
+ var import_path5 = __toESM(require("path"), 1);
5409
+ var import_node_url2 = require("url");
5410
+
5411
+ // src/commands/app/package-paths.ts
5412
+ init_cjs_shims();
5413
+ var import_fs4 = __toESM(require("fs"), 1);
5414
+ var import_path3 = __toESM(require("path"), 1);
5442
5415
  var import_node_url = require("url");
5416
+ function getCreateBasekitPackageRoot(fromDir = import_path3.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl))) {
5417
+ let dir = import_path3.default.resolve(fromDir);
5418
+ for (let i = 0; i < 8; i += 1) {
5419
+ const pkgPath = import_path3.default.join(dir, "package.json");
5420
+ if (import_fs4.default.existsSync(pkgPath)) {
5421
+ try {
5422
+ const name = JSON.parse(import_fs4.default.readFileSync(pkgPath, "utf8")).name;
5423
+ if (name === "@appsbyme/create-basekit") {
5424
+ return dir;
5425
+ }
5426
+ } catch {
5427
+ }
5428
+ }
5429
+ const parent = import_path3.default.dirname(dir);
5430
+ if (parent === dir) break;
5431
+ dir = parent;
5432
+ }
5433
+ throw new Error(
5434
+ `Could not find @appsbyme/create-basekit package root (started at ${fromDir})`
5435
+ );
5436
+ }
5443
5437
 
5444
5438
  // src/commands/web/spinner.ts
5445
5439
  init_cjs_shims();
@@ -5473,8 +5467,8 @@ function createSpinner2(text) {
5473
5467
  // src/commands/web/utils.ts
5474
5468
  init_cjs_shims();
5475
5469
  var import_child_process2 = require("child_process");
5476
- var import_fs4 = __toESM(require("fs"), 1);
5477
- var import_path3 = __toESM(require("path"), 1);
5470
+ var import_fs5 = __toESM(require("fs"), 1);
5471
+ var import_path4 = __toESM(require("path"), 1);
5478
5472
  function logStep2(msg) {
5479
5473
  console.log(`
5480
5474
  \u25B6 ${msg}`);
@@ -5492,27 +5486,27 @@ function logError2(msg) {
5492
5486
  console.error(` \u2717 ${msg}`);
5493
5487
  }
5494
5488
  function exists2(absPath) {
5495
- return import_fs4.default.existsSync(absPath);
5489
+ return import_fs5.default.existsSync(absPath);
5496
5490
  }
5497
5491
  function copyDir(src, dest) {
5498
- import_fs4.default.cpSync(src, dest, { recursive: true });
5492
+ import_fs5.default.cpSync(src, dest, { recursive: true });
5499
5493
  }
5500
5494
  function readText2(absPath) {
5501
- return import_fs4.default.readFileSync(absPath, "utf-8");
5495
+ return import_fs5.default.readFileSync(absPath, "utf-8");
5502
5496
  }
5503
5497
  function writeText2(absPath, content) {
5504
- import_fs4.default.writeFileSync(absPath, content);
5498
+ import_fs5.default.writeFileSync(absPath, content);
5505
5499
  }
5506
5500
  function readJson(absPath) {
5507
- return JSON.parse(import_fs4.default.readFileSync(absPath, "utf-8"));
5501
+ return JSON.parse(import_fs5.default.readFileSync(absPath, "utf-8"));
5508
5502
  }
5509
5503
  function writeJson(absPath, data) {
5510
- import_fs4.default.writeFileSync(absPath, JSON.stringify(data, null, 2) + "\n");
5504
+ import_fs5.default.writeFileSync(absPath, JSON.stringify(data, null, 2) + "\n");
5511
5505
  }
5512
5506
  function safeUnlink2(absPath) {
5513
5507
  if (!exists2(absPath)) return false;
5514
5508
  try {
5515
- import_fs4.default.unlinkSync(absPath);
5509
+ import_fs5.default.unlinkSync(absPath);
5516
5510
  return true;
5517
5511
  } catch {
5518
5512
  return false;
@@ -5521,7 +5515,7 @@ function safeUnlink2(absPath) {
5521
5515
  function safeRmDir(absDir) {
5522
5516
  if (!exists2(absDir)) return false;
5523
5517
  try {
5524
- import_fs4.default.rmSync(absDir, { recursive: true, force: true });
5518
+ import_fs5.default.rmSync(absDir, { recursive: true, force: true });
5525
5519
  return true;
5526
5520
  } catch {
5527
5521
  return false;
@@ -5589,7 +5583,7 @@ function removeMarkedSection(content, marker) {
5589
5583
  return content.replace(regex, "\n");
5590
5584
  }
5591
5585
  function getDestDir(appName) {
5592
- return import_path3.default.resolve(process.cwd(), appName);
5586
+ return import_path4.default.resolve(process.cwd(), appName);
5593
5587
  }
5594
5588
  function patchReplace(content, pattern, replacement, description) {
5595
5589
  const result = content.replace(pattern, replacement);
@@ -5601,23 +5595,15 @@ function patchReplace(content, pattern, replacement, description) {
5601
5595
 
5602
5596
  // src/commands/web/scaffold.ts
5603
5597
  function templateDir() {
5604
- const here = import_path4.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
5605
- const candidates = [
5606
- import_path4.default.join(here, "../../../template-web"),
5607
- import_path4.default.join(here, "../template-web")
5608
- ];
5609
- for (const candidate of candidates) {
5610
- const resolved = import_path4.default.resolve(candidate);
5611
- if (import_fs5.default.existsSync(resolved)) return resolved;
5612
- }
5613
- throw new Error(
5614
- `Starter template is missing (searched: ${candidates.map((c) => import_path4.default.resolve(c)).join(", ")})`
5598
+ return import_path5.default.join(
5599
+ getCreateBasekitPackageRoot(import_path5.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl))),
5600
+ "template-web"
5615
5601
  );
5616
5602
  }
5617
5603
  async function scaffold(opts) {
5618
5604
  const { appName, description, destDir, enableTailwind, enablePwa, enableDocker, enableHusky } = opts;
5619
5605
  if (exists2(destDir)) {
5620
- throw new Error(`Directory "${import_path4.default.basename(destDir)}" already exists.`);
5606
+ throw new Error(`Directory "${import_path5.default.basename(destDir)}" already exists.`);
5621
5607
  }
5622
5608
  try {
5623
5609
  await scaffoldInner(opts);
@@ -5634,10 +5620,11 @@ async function scaffoldInner(opts) {
5634
5620
  const { appName, description, destDir, enableTailwind, enablePwa, enableDocker, enableHusky, portOffset } = opts;
5635
5621
  await cloneTemplate(destDir);
5636
5622
  materializeGitignore(destDir);
5637
- safeUnlink2(import_path4.default.join(destDir, "yarn.lock"));
5638
- safeRmDir(import_path4.default.join(destDir, ".git"));
5623
+ materializeYarnrc(destDir);
5624
+ safeUnlink2(import_path5.default.join(destDir, "yarn.lock"));
5625
+ safeRmDir(import_path5.default.join(destDir, ".git"));
5639
5626
  logOk2("Removed .git history \u2014 clean slate");
5640
- safeUnlink2(import_path4.default.join(destDir, "commitlint.config.js"));
5627
+ safeUnlink2(import_path5.default.join(destDir, "commitlint.config.js"));
5641
5628
  cleanupGitignore(destDir);
5642
5629
  logStep2("Customising template");
5643
5630
  replaceTokens(destDir, appName, description);
@@ -5676,7 +5663,7 @@ async function scaffoldInner(opts) {
5676
5663
  }
5677
5664
  async function cloneTemplate(destDir) {
5678
5665
  const source = templateDir();
5679
- if (!import_fs5.default.existsSync(source)) {
5666
+ if (!import_fs6.default.existsSync(source)) {
5680
5667
  throw new Error(`Starter template is missing at ${source}`);
5681
5668
  }
5682
5669
  const spinner = createSpinner2("Copying starter template\u2026");
@@ -5689,16 +5676,21 @@ async function cloneTemplate(destDir) {
5689
5676
  spinner.succeed("Template copied");
5690
5677
  }
5691
5678
  function materializeGitignore(destDir) {
5692
- const packagedPath = import_path4.default.join(destDir, "_gitignore");
5679
+ const packagedPath = import_path5.default.join(destDir, "_gitignore");
5680
+ if (!exists2(packagedPath)) return;
5681
+ import_fs6.default.renameSync(packagedPath, import_path5.default.join(destDir, ".gitignore"));
5682
+ }
5683
+ function materializeYarnrc(destDir) {
5684
+ const packagedPath = import_path5.default.join(destDir, "_yarnrc.yml");
5693
5685
  if (!exists2(packagedPath)) return;
5694
- import_fs5.default.renameSync(packagedPath, import_path4.default.join(destDir, ".gitignore"));
5686
+ import_fs6.default.renameSync(packagedPath, import_path5.default.join(destDir, ".yarnrc.yml"));
5695
5687
  }
5696
5688
  var TEMPLATE_TITLE = "React Starter Kit";
5697
5689
  var TEMPLATE_DESCRIPTION = "A modern React starter kit with TypeScript, Vite, SCSS, and comprehensive tooling for building scalable applications";
5698
5690
  function replaceTokens(destDir, appName, description) {
5699
5691
  const pkgName = toPackageName(appName);
5700
5692
  const appTitle = toTitle(appName);
5701
- const pkgPath = import_path4.default.join(destDir, "package.json");
5693
+ const pkgPath = import_path5.default.join(destDir, "package.json");
5702
5694
  if (exists2(pkgPath)) {
5703
5695
  const pkg = readJson(pkgPath);
5704
5696
  pkg["name"] = pkgName;
@@ -5713,7 +5705,7 @@ function replaceTokens(destDir, appName, description) {
5713
5705
  writeJson(pkgPath, pkg);
5714
5706
  logOk2("package.json \u2014 name, description, version, stripped monorepo fields");
5715
5707
  }
5716
- const indexPath = import_path4.default.join(destDir, "index.html");
5708
+ const indexPath = import_path5.default.join(destDir, "index.html");
5717
5709
  if (exists2(indexPath)) {
5718
5710
  let html = readText2(indexPath);
5719
5711
  html = html.replace(
@@ -5731,7 +5723,7 @@ function replaceTokens(destDir, appName, description) {
5731
5723
  writeText2(indexPath, html);
5732
5724
  logOk2("index.html \u2014 title, meta description, application-name");
5733
5725
  }
5734
- const configPath = import_path4.default.join(destDir, "src", "configs", "appConfig.ts");
5726
+ const configPath = import_path5.default.join(destDir, "src", "configs", "appConfig.ts");
5735
5727
  if (exists2(configPath)) {
5736
5728
  let cfg = readText2(configPath);
5737
5729
  cfg = cfg.replace(
@@ -5741,7 +5733,7 @@ function replaceTokens(destDir, appName, description) {
5741
5733
  writeText2(configPath, cfg);
5742
5734
  logOk2("src/configs/appConfig.ts \u2014 default title");
5743
5735
  }
5744
- const readmePath = import_path4.default.join(destDir, "README.md");
5736
+ const readmePath = import_path5.default.join(destDir, "README.md");
5745
5737
  if (exists2(readmePath)) {
5746
5738
  let readme = readText2(readmePath);
5747
5739
  readme = readme.replace(
@@ -5755,7 +5747,7 @@ function replaceTokens(destDir, appName, description) {
5755
5747
  writeText2(readmePath, readme);
5756
5748
  logOk2("README.md \u2014 heading");
5757
5749
  }
5758
- const manifestPath = import_path4.default.join(destDir, "public", "manifest.webmanifest");
5750
+ const manifestPath = import_path5.default.join(destDir, "public", "manifest.webmanifest");
5759
5751
  if (exists2(manifestPath)) {
5760
5752
  let manifest = readText2(manifestPath);
5761
5753
  manifest = manifest.replace(
@@ -5767,7 +5759,7 @@ function replaceTokens(destDir, appName, description) {
5767
5759
  }
5768
5760
  }
5769
5761
  function patchDockerComposeForProject(destDir, appName, portOffset) {
5770
- const composePath = import_path4.default.join(destDir, "docker-compose.yml");
5762
+ const composePath = import_path5.default.join(destDir, "docker-compose.yml");
5771
5763
  if (!exists2(composePath)) return;
5772
5764
  logStep2("Patching docker-compose.yml \u2014 container names + ports");
5773
5765
  let content = readText2(composePath);
@@ -5800,7 +5792,7 @@ function patchDockerComposeForProject(destDir, appName, portOffset) {
5800
5792
  }
5801
5793
  }
5802
5794
  function patchMakefileForProject(destDir, appName) {
5803
- const makefilePath = import_path4.default.join(destDir, "Makefile");
5795
+ const makefilePath = import_path5.default.join(destDir, "Makefile");
5804
5796
  if (!exists2(makefilePath)) return;
5805
5797
  let content = readText2(makefilePath);
5806
5798
  content = content.replace(
@@ -5813,7 +5805,7 @@ function patchMakefileForProject(destDir, appName) {
5813
5805
  logOk2("Makefile \u2014 ensured dynamic container names");
5814
5806
  }
5815
5807
  function patchViteConfigPort(destDir, portOffset) {
5816
- const configPath = import_path4.default.join(destDir, "vite.config.ts");
5808
+ const configPath = import_path5.default.join(destDir, "vite.config.ts");
5817
5809
  if (!exists2(configPath)) return;
5818
5810
  const devPort = 3e3 + portOffset;
5819
5811
  let content = readText2(configPath);
@@ -5824,7 +5816,7 @@ function patchViteConfigPort(destDir, portOffset) {
5824
5816
  function patchEnvExamplePorts(destDir, portOffset) {
5825
5817
  const bePort = 8e3 + portOffset;
5826
5818
  for (const envFile of [".env.example", ".env.local"]) {
5827
- const envPath = import_path4.default.join(destDir, envFile);
5819
+ const envPath = import_path5.default.join(destDir, envFile);
5828
5820
  if (!exists2(envPath)) continue;
5829
5821
  let content = readText2(envPath);
5830
5822
  content = patchReplace(
@@ -5841,17 +5833,17 @@ function removeDocker(destDir) {
5841
5833
  const files = ["Dockerfile", "docker-compose.yml", ".dockerignore", "nginx.conf"];
5842
5834
  let deleted = 0;
5843
5835
  for (const f of files) {
5844
- if (safeUnlink2(import_path4.default.join(destDir, f))) deleted++;
5836
+ if (safeUnlink2(import_path5.default.join(destDir, f))) deleted++;
5845
5837
  }
5846
- if (safeRmDir(import_path4.default.join(destDir, "nginx"))) {
5838
+ if (safeRmDir(import_path5.default.join(destDir, "nginx"))) {
5847
5839
  deleted++;
5848
5840
  logInfo2("nginx/ \u2014 removed");
5849
5841
  }
5850
- if (safeUnlink2(import_path4.default.join(destDir, "Makefile"))) {
5842
+ if (safeUnlink2(import_path5.default.join(destDir, "Makefile"))) {
5851
5843
  deleted++;
5852
5844
  logInfo2("Makefile \u2014 removed");
5853
5845
  }
5854
- const readmePath = import_path4.default.join(destDir, "README.md");
5846
+ const readmePath = import_path5.default.join(destDir, "README.md");
5855
5847
  if (exists2(readmePath)) {
5856
5848
  let readme = readText2(readmePath);
5857
5849
  readme = removeMarkedSection(readme, "DOCKER");
@@ -5861,7 +5853,7 @@ function removeDocker(destDir) {
5861
5853
  writeText2(readmePath, readme);
5862
5854
  logInfo2("README.md \u2014 removed Docker sections");
5863
5855
  }
5864
- const envExPath = import_path4.default.join(destDir, ".env.example");
5856
+ const envExPath = import_path5.default.join(destDir, ".env.example");
5865
5857
  if (exists2(envExPath)) {
5866
5858
  let env = readText2(envExPath);
5867
5859
  env = env.replace(/# -{5,}\s*\n# 🐳 Docker[^#]*/g, "");
@@ -5884,16 +5876,16 @@ var PWA_FILES = [
5884
5876
  function removePwa(destDir) {
5885
5877
  let deleted = 0;
5886
5878
  for (const f of PWA_FILES) {
5887
- if (safeUnlink2(import_path4.default.join(destDir, f))) deleted++;
5879
+ if (safeUnlink2(import_path5.default.join(destDir, f))) deleted++;
5888
5880
  }
5889
- if (safeRmDir(import_path4.default.join(destDir, "public", "icons"))) deleted++;
5890
- safeRmDir(import_path4.default.join(destDir, "src", "sw"));
5891
- safeRmDir(import_path4.default.join(destDir, "src", "pwa"));
5881
+ if (safeRmDir(import_path5.default.join(destDir, "public", "icons"))) deleted++;
5882
+ safeRmDir(import_path5.default.join(destDir, "src", "sw"));
5883
+ safeRmDir(import_path5.default.join(destDir, "src", "pwa"));
5892
5884
  removePwaFromPackageJson(destDir);
5893
5885
  removePwaFromPluginsIndex(destDir);
5894
5886
  removePwaFromViteConfig(destDir);
5895
5887
  removePwaFromIndexHtml(destDir);
5896
- const readmePath = import_path4.default.join(destDir, "README.md");
5888
+ const readmePath = import_path5.default.join(destDir, "README.md");
5897
5889
  if (exists2(readmePath)) {
5898
5890
  let readme = readText2(readmePath);
5899
5891
  readme = removeMarkedSection(readme, "PWA");
@@ -5908,7 +5900,7 @@ function removePwa(destDir) {
5908
5900
  logOk2(`Deleted ${deleted} PWA file(s)`);
5909
5901
  }
5910
5902
  function removePwaFromPackageJson(destDir) {
5911
- const pkgPath = import_path4.default.join(destDir, "package.json");
5903
+ const pkgPath = import_path5.default.join(destDir, "package.json");
5912
5904
  if (!exists2(pkgPath)) return;
5913
5905
  const pkg = readJson(pkgPath);
5914
5906
  let changed = false;
@@ -5929,7 +5921,7 @@ function removePwaFromPackageJson(destDir) {
5929
5921
  removePkgScript(destDir, "setup:pwa");
5930
5922
  }
5931
5923
  function removePwaFromPluginsIndex(destDir) {
5932
- const indexPath = import_path4.default.join(destDir, "plugins", "index.ts");
5924
+ const indexPath = import_path5.default.join(destDir, "plugins", "index.ts");
5933
5925
  if (!exists2(indexPath)) return;
5934
5926
  let content = readText2(indexPath);
5935
5927
  content = content.replace(/^.*pwaPlugin.*\n/gm, "");
@@ -5941,7 +5933,7 @@ function removePwaFromPluginsIndex(destDir) {
5941
5933
  logInfo2("plugins/index.ts \u2014 removed PWA plugin exports");
5942
5934
  }
5943
5935
  function removePwaFromViteConfig(destDir) {
5944
- const configPath = import_path4.default.join(destDir, "vite.config.ts");
5936
+ const configPath = import_path5.default.join(destDir, "vite.config.ts");
5945
5937
  if (!exists2(configPath)) return;
5946
5938
  let content = readText2(configPath);
5947
5939
  content = content.replace(
@@ -5962,7 +5954,7 @@ function removePwaFromViteConfig(destDir) {
5962
5954
  logInfo2("vite.config.ts \u2014 removed PWA plugin usage");
5963
5955
  }
5964
5956
  function removePwaFromIndexHtml(destDir) {
5965
- const indexPath = import_path4.default.join(destDir, "index.html");
5957
+ const indexPath = import_path5.default.join(destDir, "index.html");
5966
5958
  if (!exists2(indexPath)) return;
5967
5959
  let html = readText2(indexPath);
5968
5960
  html = html.replace(/\s*<link rel="manifest"[^>]*>\s*/g, "\n ");
@@ -5980,7 +5972,7 @@ function removePwaFromIndexHtml(destDir) {
5980
5972
  logInfo2("index.html \u2014 removed PWA meta tags and manifest link");
5981
5973
  }
5982
5974
  function removePwaFromMainTsx(destDir) {
5983
- const mainPath = import_path4.default.join(destDir, "src", "main.tsx");
5975
+ const mainPath = import_path5.default.join(destDir, "src", "main.tsx");
5984
5976
  if (!exists2(mainPath)) return;
5985
5977
  let content = readText2(mainPath);
5986
5978
  content = content.replace(/^import\s*\{[^}]*initPWA[^}]*\}\s*from\s*['"][^'"]*pwa['"];\s*\n/gm, "");
@@ -5990,7 +5982,7 @@ function removePwaFromMainTsx(destDir) {
5990
5982
  logInfo2("src/main.tsx \u2014 removed initPWA import and call");
5991
5983
  }
5992
5984
  function removePwaFromAppTsx(destDir) {
5993
- const appPath = import_path4.default.join(destDir, "src", "App.tsx");
5985
+ const appPath = import_path5.default.join(destDir, "src", "App.tsx");
5994
5986
  if (!exists2(appPath)) return;
5995
5987
  let content = readText2(appPath);
5996
5988
  content = content.replace(/,\s*PwaUpdateBanner\b/g, "");
@@ -6001,11 +5993,11 @@ function removePwaFromAppTsx(destDir) {
6001
5993
  logInfo2("src/App.tsx \u2014 removed PwaUpdateBanner");
6002
5994
  }
6003
5995
  function removeHusky(destDir) {
6004
- const huskyDir = import_path4.default.join(destDir, ".husky");
5996
+ const huskyDir = import_path5.default.join(destDir, ".husky");
6005
5997
  if (safeRmDir(huskyDir)) {
6006
5998
  logInfo2(".husky/ \u2014 removed");
6007
5999
  }
6008
- const pkgPath = import_path4.default.join(destDir, "package.json");
6000
+ const pkgPath = import_path5.default.join(destDir, "package.json");
6009
6001
  if (exists2(pkgPath)) {
6010
6002
  const pkg = readJson(pkgPath);
6011
6003
  let changed = false;
@@ -6045,7 +6037,7 @@ function addTailwind(destDir) {
6045
6037
  importTailwindInMain(destDir);
6046
6038
  }
6047
6039
  function addTailwindDeps(destDir) {
6048
- const pkgPath = import_path4.default.join(destDir, "package.json");
6040
+ const pkgPath = import_path5.default.join(destDir, "package.json");
6049
6041
  if (!exists2(pkgPath)) return;
6050
6042
  const pkg = readJson(pkgPath);
6051
6043
  const devDeps = pkg["devDependencies"] ?? {};
@@ -6056,7 +6048,7 @@ function addTailwindDeps(destDir) {
6056
6048
  logOk2("package.json \u2014 added tailwindcss + @tailwindcss/vite");
6057
6049
  }
6058
6050
  function addTailwindVitePlugin(destDir) {
6059
- const configPath = import_path4.default.join(destDir, "vite.config.ts");
6051
+ const configPath = import_path5.default.join(destDir, "vite.config.ts");
6060
6052
  if (!exists2(configPath)) return;
6061
6053
  let content = readText2(configPath);
6062
6054
  if (!content.includes("@tailwindcss/vite")) {
@@ -6127,12 +6119,12 @@ function createTailwindCss(destDir) {
6127
6119
  --radius-lg: var(--radius-4);
6128
6120
  }
6129
6121
  `;
6130
- const stylesDir = import_path4.default.join(destDir, "src", "styles");
6131
- writeText2(import_path4.default.join(stylesDir, "tailwind.css"), tailwindCss);
6122
+ const stylesDir = import_path5.default.join(destDir, "src", "styles");
6123
+ writeText2(import_path5.default.join(stylesDir, "tailwind.css"), tailwindCss);
6132
6124
  logOk2("src/styles/tailwind.css \u2014 created with theme bridge");
6133
6125
  }
6134
6126
  function importTailwindInMain(destDir) {
6135
- const mainPath = import_path4.default.join(destDir, "src", "main.tsx");
6127
+ const mainPath = import_path5.default.join(destDir, "src", "main.tsx");
6136
6128
  if (!exists2(mainPath)) return;
6137
6129
  let content = readText2(mainPath);
6138
6130
  const tailwindImport = "import '@styles/tailwind.css';";
@@ -6166,7 +6158,7 @@ function cleanupSetupScripts(destDir, opts) {
6166
6158
  if (scriptsToRemove.length === 0) return;
6167
6159
  logStep2("Removing unused setup scripts");
6168
6160
  for (const script of scriptsToRemove) {
6169
- const scriptPath = import_path4.default.join(destDir, "scripts", script);
6161
+ const scriptPath = import_path5.default.join(destDir, "scripts", script);
6170
6162
  if (safeUnlink2(scriptPath)) {
6171
6163
  logOk2(`scripts/${script} \u2014 removed`);
6172
6164
  }
@@ -6243,11 +6235,11 @@ function injectBrandColors(destDir, opts) {
6243
6235
  "}",
6244
6236
  ""
6245
6237
  ].join("\n");
6246
- const themesDir = import_path4.default.join(destDir, "src", "styles", "themes");
6247
- const brandPath = import_path4.default.join(themesDir, "_brand.scss");
6238
+ const themesDir = import_path5.default.join(destDir, "src", "styles", "themes");
6239
+ const brandPath = import_path5.default.join(themesDir, "_brand.scss");
6248
6240
  writeText2(brandPath, brandScss);
6249
6241
  logOk2("src/styles/themes/_brand.scss \u2014 created");
6250
- const indexPath = import_path4.default.join(themesDir, "_index.scss");
6242
+ const indexPath = import_path5.default.join(themesDir, "_index.scss");
6251
6243
  if (exists2(indexPath)) {
6252
6244
  let idx = readText2(indexPath);
6253
6245
  if (!idx.includes("@forward './brand'")) {
@@ -6258,8 +6250,8 @@ function injectBrandColors(destDir, opts) {
6258
6250
  }
6259
6251
  }
6260
6252
  function generateEnvLocal(destDir, appName) {
6261
- const examplePath = import_path4.default.join(destDir, ".env.example");
6262
- const localPath = import_path4.default.join(destDir, ".env.local");
6253
+ const examplePath = import_path5.default.join(destDir, ".env.example");
6254
+ const localPath = import_path5.default.join(destDir, ".env.local");
6263
6255
  if (!exists2(examplePath)) {
6264
6256
  logInfo2(".env.example not found \u2014 skipping .env.local generation");
6265
6257
  return;
@@ -6274,7 +6266,7 @@ function generateEnvLocal(destDir, appName) {
6274
6266
  logOk2(".env.local generated from .env.example");
6275
6267
  }
6276
6268
  function cleanupGitignore(destDir) {
6277
- const gitignorePath = import_path4.default.join(destDir, ".gitignore");
6269
+ const gitignorePath = import_path5.default.join(destDir, ".gitignore");
6278
6270
  if (!exists2(gitignorePath)) return;
6279
6271
  let content = readText2(gitignorePath);
6280
6272
  const monorepoPatterns = [
@@ -6306,7 +6298,7 @@ function cleanupTemplateDocs(destDir) {
6306
6298
  logStep2("Removing template documentation files");
6307
6299
  let removed = 0;
6308
6300
  for (const f of docFiles) {
6309
- if (safeUnlink2(import_path4.default.join(destDir, f))) {
6301
+ if (safeUnlink2(import_path5.default.join(destDir, f))) {
6310
6302
  logOk2(`${f} \u2014 removed`);
6311
6303
  removed++;
6312
6304
  }
@@ -6342,7 +6334,7 @@ function initGitRepo(destDir, appName) {
6342
6334
  }
6343
6335
  }
6344
6336
  function removePkgScript(destDir, scriptName) {
6345
- const pkgPath = import_path4.default.join(destDir, "package.json");
6337
+ const pkgPath = import_path5.default.join(destDir, "package.json");
6346
6338
  if (!exists2(pkgPath)) return;
6347
6339
  const pkg = readJson(pkgPath);
6348
6340
  const scripts = pkg["scripts"];
@@ -6415,7 +6407,7 @@ async function runWebCommand(argv) {
6415
6407
  return;
6416
6408
  }
6417
6409
  if (args.includes("--version") || args.includes("-v")) {
6418
- console.log("1.0.4");
6410
+ console.log("1.0.5");
6419
6411
  return;
6420
6412
  }
6421
6413
  printBanner();
@@ -6430,7 +6422,7 @@ async function runWebCommand(argv) {
6430
6422
  const destDir2 = getDestDir(appName2);
6431
6423
  const pm2 = detectDefaultPm();
6432
6424
  console.log("");
6433
- logStep2(`Creating "${appName2}" (non-interactive) in ${import_path5.default.relative(process.cwd(), import_path5.default.dirname(destDir2))}`);
6425
+ logStep2(`Creating "${appName2}" (non-interactive) in ${import_path6.default.relative(process.cwd(), import_path6.default.dirname(destDir2))}`);
6434
6426
  try {
6435
6427
  await scaffold({
6436
6428
  appName: appName2,
@@ -6579,7 +6571,7 @@ async function runWebCommand(argv) {
6579
6571
  const appName = toPackageName(argName ?? answers.appName ?? "my-web-app");
6580
6572
  const destDir = getDestDir(appName);
6581
6573
  console.log("");
6582
- logStep2(`Creating "${appName}" in ${import_path5.default.relative(process.cwd(), import_path5.default.dirname(destDir))}`);
6574
+ logStep2(`Creating "${appName}" in ${import_path6.default.relative(process.cwd(), import_path6.default.dirname(destDir))}`);
6583
6575
  try {
6584
6576
  await scaffold({
6585
6577
  appName,
@@ -6619,19 +6611,19 @@ async function runWebCommand(argv) {
6619
6611
  function printBanner() {
6620
6612
  console.log("");
6621
6613
  console.log(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
6622
- console.log(` \u2551 create-basekit web v${"1.0.4"} \u2551`);
6614
+ console.log(` \u2551 create-basekit web v${"1.0.5"} \u2551`);
6623
6615
  console.log(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D");
6624
6616
  console.log("");
6625
6617
  }
6626
6618
  function abortIfInsideWorkspace(argv) {
6627
6619
  const exampleName = argv.find((a) => !a.startsWith("-") && !isValueOfFlag(argv, a))?.trim() ?? "my-app";
6628
6620
  let dir = process.cwd();
6629
- const root = import_path5.default.parse(dir).root;
6621
+ const root = import_path6.default.parse(dir).root;
6630
6622
  while (dir !== root) {
6631
- const pkgPath = import_path5.default.join(dir, "package.json");
6632
- if (import_fs6.default.existsSync(pkgPath)) {
6623
+ const pkgPath = import_path6.default.join(dir, "package.json");
6624
+ if (import_fs7.default.existsSync(pkgPath)) {
6633
6625
  try {
6634
- const pkg = JSON.parse(import_fs6.default.readFileSync(pkgPath, "utf8"));
6626
+ const pkg = JSON.parse(import_fs7.default.readFileSync(pkgPath, "utf8"));
6635
6627
  if (pkg.workspaces) {
6636
6628
  console.error("");
6637
6629
  console.error(" \u2717 Cannot create app inside a Yarn workspace.");
@@ -6653,7 +6645,7 @@ function abortIfInsideWorkspace(argv) {
6653
6645
  } catch {
6654
6646
  }
6655
6647
  }
6656
- const parent = import_path5.default.dirname(dir);
6648
+ const parent = import_path6.default.dirname(dir);
6657
6649
  if (parent === dir) break;
6658
6650
  dir = parent;
6659
6651
  }
@@ -6725,82 +6717,12 @@ function isValueOfFlag(args, value) {
6725
6717
  return prev !== void 0 && prev.startsWith("--");
6726
6718
  }
6727
6719
 
6728
- // src/commands/app/local-basekit-pins.ts
6729
- init_cjs_shims();
6730
- var import_path6 = __toESM(require("path"), 1);
6731
- var BASEKIT_PACKAGE_DIRS = {
6732
- "@appsbyme/basekit-hooks": "hooks",
6733
- "@appsbyme/basekit-styles": "styles",
6734
- "@appsbyme/basekit-ui": "ui",
6735
- "@appsbyme/basekit-utils": "utils",
6736
- "@appsbyme/basekit-eslint-config": "eslint-config",
6737
- "@appsbyme/basekit-stylelint-config": "stylelint-config",
6738
- "@appsbyme/basekit-tsconfig": "tsconfig"
6739
- };
6740
- function webKitPackagesAvailable(webKitRoot) {
6741
- return exists(import_path6.default.join(webKitRoot, "packages", "utils", "package.json"));
6742
- }
6743
- function toFileSpecifier(fromDir, absolutePackageDir) {
6744
- let relative = import_path6.default.relative(fromDir, absolutePackageDir);
6745
- if (!relative.startsWith(".")) {
6746
- relative = `./${relative}`;
6747
- }
6748
- return `file:${relative.replace(/\\/g, "/")}`;
6749
- }
6750
- function rewriteSection(section, frontendDir, webKitRoot) {
6751
- if (!section) return 0;
6752
- let count = 0;
6753
- for (const [name, dirName] of Object.entries(BASEKIT_PACKAGE_DIRS)) {
6754
- if (!(name in section)) continue;
6755
- const absolute = import_path6.default.join(webKitRoot, "packages", dirName);
6756
- if (!exists(import_path6.default.join(absolute, "package.json"))) {
6757
- logWarn(`Local package missing for ${name} \u2014 left as ${section[name]}`);
6758
- continue;
6759
- }
6760
- section[name] = toFileSpecifier(frontendDir, absolute);
6761
- count += 1;
6762
- }
6763
- return count;
6764
- }
6765
- function applyLocalBasekitPins(projectRoot, webKitRoot = getWebKitRootFromPackage()) {
6766
- if (!webKitPackagesAvailable(webKitRoot)) {
6767
- logInfo("Local basekit-web packages not found \u2014 leaving @appsbyme registry pins");
6768
- return false;
6769
- }
6770
- const packageJsonPath = import_path6.default.join(projectRoot, "frontend", "package.json");
6771
- if (!exists(packageJsonPath)) {
6772
- logWarn("frontend/package.json not found \u2014 skipping local @appsbyme pins");
6773
- return false;
6774
- }
6775
- const pkg = JSON.parse(readText(packageJsonPath));
6776
- const frontendDir = import_path6.default.join(projectRoot, "frontend");
6777
- let rewritten = rewriteSection(pkg.dependencies, frontendDir, webKitRoot) + rewriteSection(pkg.devDependencies, frontendDir, webKitRoot) + rewriteSection(pkg.resolutions, frontendDir, webKitRoot);
6778
- if (!pkg.resolutions) pkg.resolutions = {};
6779
- for (const [name, dirName] of Object.entries(BASEKIT_PACKAGE_DIRS)) {
6780
- const absolute = import_path6.default.join(webKitRoot, "packages", dirName);
6781
- if (!exists(import_path6.default.join(absolute, "package.json"))) continue;
6782
- const next = toFileSpecifier(frontendDir, absolute);
6783
- if (pkg.resolutions[name] !== next) {
6784
- pkg.resolutions[name] = next;
6785
- rewritten += 1;
6786
- }
6787
- }
6788
- if (rewritten === 0) {
6789
- logInfo("No @appsbyme pins to rewrite in frontend/package.json");
6790
- return false;
6791
- }
6792
- writeText(packageJsonPath, `${JSON.stringify(pkg, null, 2)}
6793
- `);
6794
- logOk(`Rewrote ${rewritten} @appsbyme pin(s) to local file: paths`);
6795
- return true;
6796
- }
6797
-
6798
6720
  // src/commands/app/yarn-install.ts
6799
6721
  init_cjs_shims();
6800
- var import_fs7 = __toESM(require("fs"), 1);
6722
+ var import_fs8 = __toESM(require("fs"), 1);
6801
6723
  var import_path7 = __toESM(require("path"), 1);
6802
6724
  async function yarnInstall(dir, label) {
6803
- if (!import_fs7.default.existsSync(import_path7.default.join(dir, "package.json"))) {
6725
+ if (!import_fs8.default.existsSync(import_path7.default.join(dir, "package.json"))) {
6804
6726
  logWarn(`${label}/package.json not found \u2014 skipping yarn install`);
6805
6727
  return false;
6806
6728
  }
@@ -6854,7 +6776,6 @@ function buildWebScaffoldArgv(projectName, portOffset, nonInteractive) {
6854
6776
  "--port-offset",
6855
6777
  String(portOffset),
6856
6778
  "--no-git",
6857
- // Install after optional local @appsbyme file: pin rewrite (kit authors)
6858
6779
  "--no-install"
6859
6780
  ];
6860
6781
  if (nonInteractive) {
@@ -6862,6 +6783,14 @@ function buildWebScaffoldArgv(projectName, portOffset, nonInteractive) {
6862
6783
  }
6863
6784
  return args;
6864
6785
  }
6786
+ function stripNestedFrontendGithub(frontendDir) {
6787
+ const nestedGithub = import_path8.default.join(frontendDir, ".github");
6788
+ if (!import_fs9.default.existsSync(nestedGithub)) {
6789
+ return false;
6790
+ }
6791
+ import_fs9.default.rmSync(nestedGithub, { recursive: true, force: true });
6792
+ return true;
6793
+ }
6865
6794
  async function scaffoldFrontend(opts) {
6866
6795
  const { projectName, portOffset, projectRoot, nonInteractive } = opts;
6867
6796
  logStep("Running create-basekit web (answer the remaining prompts)");
@@ -6873,11 +6802,13 @@ async function scaffoldFrontend(opts) {
6873
6802
  }
6874
6803
  const scaffoldedDir = import_path8.default.join(projectRoot, projectName);
6875
6804
  const frontendDir = import_path8.default.join(projectRoot, "frontend");
6876
- if (import_fs8.default.existsSync(scaffoldedDir)) {
6877
- import_fs8.default.renameSync(scaffoldedDir, frontendDir);
6805
+ if (import_fs9.default.existsSync(scaffoldedDir)) {
6806
+ import_fs9.default.renameSync(scaffoldedDir, frontendDir);
6878
6807
  logOk(`Renamed ${projectName}/ \u2192 frontend/`);
6879
6808
  }
6880
- applyLocalBasekitPins(projectRoot);
6809
+ if (stripNestedFrontendGithub(frontendDir)) {
6810
+ logOk("Removed frontend/.github (root CI owns workflows)");
6811
+ }
6881
6812
  await yarnInstall(frontendDir, "frontend");
6882
6813
  logOk("Frontend scaffolded");
6883
6814
  }
@@ -6885,7 +6816,7 @@ async function scaffoldFrontend(opts) {
6885
6816
  // src/commands/app/mobile.ts
6886
6817
  init_cjs_shims();
6887
6818
  var import_path11 = __toESM(require("path"), 1);
6888
- var import_fs11 = __toESM(require("fs"), 1);
6819
+ var import_fs12 = __toESM(require("fs"), 1);
6889
6820
 
6890
6821
  // src/commands/mobile/index.ts
6891
6822
  init_cjs_shims();
@@ -6893,14 +6824,14 @@ var import_prompts2 = __toESM(require_prompts3(), 1);
6893
6824
 
6894
6825
  // src/commands/mobile/scaffold.ts
6895
6826
  init_cjs_shims();
6896
- var import_fs10 = __toESM(require("fs"), 1);
6827
+ var import_fs11 = __toESM(require("fs"), 1);
6897
6828
  var import_path10 = __toESM(require("path"), 1);
6898
- var import_node_url2 = require("url");
6829
+ var import_node_url3 = require("url");
6899
6830
 
6900
6831
  // src/commands/mobile/utils.ts
6901
6832
  init_cjs_shims();
6902
6833
  var import_child_process3 = require("child_process");
6903
- var import_fs9 = __toESM(require("fs"), 1);
6834
+ var import_fs10 = __toESM(require("fs"), 1);
6904
6835
  var import_path9 = __toESM(require("path"), 1);
6905
6836
  function logStep3(msg) {
6906
6837
  console.log(`
@@ -6916,21 +6847,21 @@ function logError3(msg) {
6916
6847
  console.error(` \u2717 ${msg}`);
6917
6848
  }
6918
6849
  function exists3(absPath) {
6919
- return import_fs9.default.existsSync(absPath);
6850
+ return import_fs10.default.existsSync(absPath);
6920
6851
  }
6921
6852
  function copyDir2(src, dest) {
6922
- import_fs9.default.cpSync(src, dest, { recursive: true });
6853
+ import_fs10.default.cpSync(src, dest, { recursive: true });
6923
6854
  }
6924
6855
  function readText3(absPath) {
6925
- return import_fs9.default.readFileSync(absPath, "utf-8");
6856
+ return import_fs10.default.readFileSync(absPath, "utf-8");
6926
6857
  }
6927
6858
  function writeText3(absPath, content) {
6928
- import_fs9.default.writeFileSync(absPath, content);
6859
+ import_fs10.default.writeFileSync(absPath, content);
6929
6860
  }
6930
6861
  function safeRmDir2(absDir) {
6931
6862
  if (!exists3(absDir)) return false;
6932
6863
  try {
6933
- import_fs9.default.rmSync(absDir, { recursive: true, force: true });
6864
+ import_fs10.default.rmSync(absDir, { recursive: true, force: true });
6934
6865
  return true;
6935
6866
  } catch {
6936
6867
  return false;
@@ -7025,17 +6956,9 @@ function createSpinner3(text) {
7025
6956
 
7026
6957
  // src/commands/mobile/scaffold.ts
7027
6958
  function templateDir2() {
7028
- const here = import_path10.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
7029
- const candidates = [
7030
- import_path10.default.join(here, "../../../template-mobile"),
7031
- import_path10.default.join(here, "../template-mobile")
7032
- ];
7033
- for (const candidate of candidates) {
7034
- const resolved = import_path10.default.resolve(candidate);
7035
- if (import_fs10.default.existsSync(resolved)) return resolved;
7036
- }
7037
- throw new Error(
7038
- `Starter template is missing (searched: ${candidates.map((c) => import_path10.default.resolve(c)).join(", ")})`
6959
+ return import_path10.default.join(
6960
+ getCreateBasekitPackageRoot(import_path10.default.dirname((0, import_node_url3.fileURLToPath)(importMetaUrl))),
6961
+ "template-mobile"
7039
6962
  );
7040
6963
  }
7041
6964
  async function scaffold2(opts) {
@@ -7059,6 +6982,7 @@ async function scaffoldInner2(opts) {
7059
6982
  const apiUrl = `http://localhost:${8e3 + portOffset}/api/v1`;
7060
6983
  await cloneTemplate2(destDir);
7061
6984
  materializeGitignore2(destDir);
6985
+ materializeYarnrc2(destDir);
7062
6986
  if (opts.monorepo) {
7063
6987
  stripBundledShared(destDir);
7064
6988
  adjustSharedPaths(destDir);
@@ -7080,7 +7004,7 @@ async function scaffoldInner2(opts) {
7080
7004
  }
7081
7005
  async function cloneTemplate2(destDir) {
7082
7006
  const source = templateDir2();
7083
- if (!import_fs10.default.existsSync(source)) {
7007
+ if (!import_fs11.default.existsSync(source)) {
7084
7008
  throw new Error(`Starter template is missing at ${source}`);
7085
7009
  }
7086
7010
  logStep3("Copying the Expo starter");
@@ -7097,7 +7021,12 @@ async function cloneTemplate2(destDir) {
7097
7021
  function materializeGitignore2(destDir) {
7098
7022
  const packagedPath = import_path10.default.join(destDir, "_gitignore");
7099
7023
  if (!exists3(packagedPath)) return;
7100
- import_fs10.default.renameSync(packagedPath, import_path10.default.join(destDir, ".gitignore"));
7024
+ import_fs11.default.renameSync(packagedPath, import_path10.default.join(destDir, ".gitignore"));
7025
+ }
7026
+ function materializeYarnrc2(destDir) {
7027
+ const packagedPath = import_path10.default.join(destDir, "_yarnrc.yml");
7028
+ if (!exists3(packagedPath)) return;
7029
+ import_fs11.default.renameSync(packagedPath, import_path10.default.join(destDir, ".yarnrc.yml"));
7101
7030
  }
7102
7031
  function stripBundledShared(destDir) {
7103
7032
  const sharedDir = import_path10.default.join(destDir, "packages");
@@ -7203,15 +7132,15 @@ function cleanupArtifacts(destDir) {
7203
7132
  safeRmDir2(import_path10.default.join(destDir, ".git"));
7204
7133
  const lockPath = import_path10.default.join(destDir, "yarn.lock");
7205
7134
  if (exists3(lockPath)) {
7206
- import_fs10.default.unlinkSync(lockPath);
7135
+ import_fs11.default.unlinkSync(lockPath);
7207
7136
  }
7208
7137
  const readmePath = import_path10.default.join(destDir, "README.md");
7209
7138
  if (exists3(readmePath)) {
7210
- import_fs10.default.unlinkSync(readmePath);
7139
+ import_fs11.default.unlinkSync(readmePath);
7211
7140
  }
7212
7141
  const licensePath = import_path10.default.join(destDir, "LICENSE");
7213
7142
  if (exists3(licensePath)) {
7214
- import_fs10.default.unlinkSync(licensePath);
7143
+ import_fs11.default.unlinkSync(licensePath);
7215
7144
  }
7216
7145
  }
7217
7146
  function initGitRepo2(destDir) {
@@ -7281,7 +7210,7 @@ async function runMobileCommand(argv) {
7281
7210
  return;
7282
7211
  }
7283
7212
  if (args.includes("--version") || args.includes("-v")) {
7284
- console.log("1.0.4");
7213
+ console.log("1.0.5");
7285
7214
  return;
7286
7215
  }
7287
7216
  printBanner2();
@@ -7384,7 +7313,7 @@ async function runMobileCommand(argv) {
7384
7313
  function printBanner2() {
7385
7314
  console.log("");
7386
7315
  console.log(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
7387
- console.log(` \u2551 create-basekit mobile v${"1.0.4"} \u2551`);
7316
+ console.log(` \u2551 create-basekit mobile v${"1.0.5"} \u2551`);
7388
7317
  console.log(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D");
7389
7318
  console.log("");
7390
7319
  console.log(" Expo (React Native) app scaffolder");
@@ -7489,7 +7418,7 @@ async function scaffoldMobile(opts) {
7489
7418
  const scaffoldedDir = import_path11.default.join(projectRoot, projectName);
7490
7419
  const mobileDir = import_path11.default.join(projectRoot, "mobile");
7491
7420
  if (exists(scaffoldedDir)) {
7492
- import_fs11.default.renameSync(scaffoldedDir, mobileDir);
7421
+ import_fs12.default.renameSync(scaffoldedDir, mobileDir);
7493
7422
  logOk(`Renamed ${projectName}/ \u2192 mobile/`);
7494
7423
  }
7495
7424
  return true;
@@ -7501,21 +7430,12 @@ var import_path13 = __toESM(require("path"), 1);
7501
7430
 
7502
7431
  // src/commands/app/project-identity.ts
7503
7432
  init_cjs_shims();
7504
- var import_fs12 = __toESM(require("fs"), 1);
7433
+ var import_fs13 = __toESM(require("fs"), 1);
7505
7434
  var import_path12 = __toESM(require("path"), 1);
7506
- var import_node_url3 = require("url");
7507
- function resolveNewProjectFixturePath(fromDir = import_path12.default.dirname((0, import_node_url3.fileURLToPath)(importMetaUrl))) {
7508
- const candidates = [
7509
- import_path12.default.join(fromDir, "../../../fixtures/new_project.py"),
7510
- import_path12.default.join(fromDir, "../fixtures/new_project.py")
7511
- ];
7512
- for (const candidate of candidates) {
7513
- const resolved = import_path12.default.resolve(candidate);
7514
- if (import_fs12.default.existsSync(resolved)) return resolved;
7515
- }
7516
- throw new Error(
7517
- `fixtures/new_project.py missing (searched: ${candidates.map((c) => import_path12.default.resolve(c)).join(", ")})`
7518
- );
7435
+ var import_node_url4 = require("url");
7436
+ function resolveNewProjectFixturePath(fromDir = import_path12.default.dirname((0, import_node_url4.fileURLToPath)(importMetaUrl))) {
7437
+ const fixture = import_path12.default.join(getCreateBasekitPackageRoot(fromDir), "fixtures", "new_project.py");
7438
+ return fixture;
7519
7439
  }
7520
7440
  function deriveProjectIdentity(projectName) {
7521
7441
  const slug = toPythonSlug(projectName);
@@ -7537,8 +7457,8 @@ function writeProjectIdentity(projectRoot, projectName) {
7537
7457
  mkdirp(scriptsDir);
7538
7458
  const fixturePath = resolveNewProjectFixturePath();
7539
7459
  const scriptPath = import_path12.default.join(scriptsDir, "new_project.py");
7540
- import_fs12.default.copyFileSync(fixturePath, scriptPath);
7541
- import_fs12.default.chmodSync(scriptPath, 493);
7460
+ import_fs13.default.copyFileSync(fixturePath, scriptPath);
7461
+ import_fs13.default.chmodSync(scriptPath, 493);
7542
7462
  }
7543
7463
 
7544
7464
  // src/commands/app/root-files.ts
@@ -7570,14 +7490,10 @@ function createRootFiles({
7570
7490
  logOk(".github/");
7571
7491
  mkdirp(import_path13.default.join(projectRoot, ".claude"));
7572
7492
  logOk(".claude/");
7573
- if (mobile) {
7574
- const workflowsDir = import_path13.default.join(projectRoot, ".github", "workflows");
7575
- mkdirp(workflowsDir);
7576
- writeText(import_path13.default.join(workflowsDir, "ci.yml"), githubCi(projectName, frontend));
7577
- logOk(".github/workflows/ci.yml");
7578
- writeText(import_path13.default.join(projectRoot, ".github", "dependabot.yml"), githubDependabot(frontend));
7579
- logOk(".github/dependabot.yml");
7580
- }
7493
+ const workflowsDir = import_path13.default.join(projectRoot, ".github", "workflows");
7494
+ mkdirp(workflowsDir);
7495
+ writeText(import_path13.default.join(workflowsDir, "ci.yml"), githubCi(projectName, frontend, mobile));
7496
+ logOk(".github/workflows/ci.yml");
7581
7497
  }
7582
7498
  function rootReadme(projectName, portOffset, mobile, frontend = true) {
7583
7499
  const bePort = 8e3 + portOffset;
@@ -7903,7 +7819,7 @@ function rootMakefile(mobile, frontend = true) {
7903
7819
  ` : "";
7904
7820
  const feStop = frontend ? ' @pkill -f "[v]ite" >/dev/null 2>&1 || true\n' : "";
7905
7821
  const feTarget = frontend ? `
7906
- start-fe: ## Start frontend only (host yarn \u2014 works with local @appsbyme file: pins)
7822
+ start-fe: ## Start frontend only (host yarn)
7907
7823
  @cd frontend && yarn dev
7908
7824
  ` : "";
7909
7825
  const setupFe = frontend ? " @cd frontend && yarn install\n" : "";
@@ -7971,32 +7887,95 @@ ${setupTarget}${feTarget}${mobileTargets}stop: ## Stop all running services
7971
7887
  ${feStop}${mobile ? ' @pkill -f "[e]xpo start" >/dev/null 2>&1 || true\n' : ""} @echo "Done."
7972
7888
  `;
7973
7889
  }
7974
- function githubCi(projectName, frontend = true) {
7890
+ function githubCi(projectName, frontend = true, mobile = false) {
7891
+ const dockerNeeds = frontend ? "[backend, frontend]" : "[backend]";
7892
+ const frontendDockerStep = frontend ? `
7893
+ - name: Build frontend image
7894
+ run: docker build -f frontend/Dockerfile -t ${projectName}-fe:\${{ github.sha }} .
7895
+ ` : "";
7896
+ const frontendSharedInstall = mobile ? `
7897
+ - name: Install shared dependencies
7898
+ working-directory: packages/shared
7899
+ run: yarn install --immutable
7900
+ ` : "";
7901
+ const frontendCachePath = mobile ? `|
7902
+ frontend/yarn.lock
7903
+ packages/shared/yarn.lock` : "frontend/yarn.lock";
7975
7904
  const frontendJob = frontend ? `
7976
7905
  frontend:
7977
- name: Frontend (Node)
7906
+ name: "Frontend \u2014 type-check + lint + test"
7978
7907
  runs-on: ubuntu-latest
7979
7908
  defaults:
7980
7909
  run:
7981
7910
  working-directory: frontend
7982
7911
  steps:
7983
7912
  - uses: actions/checkout@v4
7913
+ - name: Enable Corepack (Yarn 4)
7914
+ run: corepack enable
7984
7915
  - uses: actions/setup-node@v4
7985
7916
  with:
7986
- node-version: 20
7987
- - run: corepack enable
7917
+ node-version: 22
7918
+ cache: yarn
7919
+ cache-dependency-path: ${frontendCachePath}
7920
+ ${frontendSharedInstall} - run: yarn install --immutable
7921
+ - run: yarn type-check
7922
+ - run: yarn lint
7923
+ - run: yarn stylelint
7924
+ - run: yarn test:run
7925
+ - run: yarn build
7926
+ ` : "";
7927
+ const mobileJobs = mobile ? `
7928
+ mobile:
7929
+ name: "Mobile \u2014 type-check + lint + test"
7930
+ runs-on: ubuntu-latest
7931
+ defaults:
7932
+ run:
7933
+ working-directory: mobile
7934
+ steps:
7935
+ - uses: actions/checkout@v4
7936
+ - name: Enable Corepack (Yarn 4)
7937
+ run: corepack enable
7938
+ - uses: actions/setup-node@v4
7939
+ with:
7940
+ node-version: 22
7941
+ cache: yarn
7942
+ cache-dependency-path: |
7943
+ mobile/yarn.lock
7944
+ packages/shared/yarn.lock
7988
7945
  - run: yarn install --immutable
7946
+ - name: Install shared dependencies
7947
+ working-directory: packages/shared
7948
+ run: yarn install --immutable
7949
+ - run: yarn type-check
7989
7950
  - run: yarn lint
7990
- - run: npx tsc --noEmit
7991
- - run: yarn test --run
7951
+ - run: yarn test --watchman=false
7952
+
7953
+ shared:
7954
+ name: "Shared \u2014 type-check + test"
7955
+ runs-on: ubuntu-latest
7956
+ defaults:
7957
+ run:
7958
+ working-directory: packages/shared
7959
+ steps:
7960
+ - uses: actions/checkout@v4
7961
+ - name: Enable Corepack (Yarn 4)
7962
+ run: corepack enable
7963
+ - uses: actions/setup-node@v4
7964
+ with:
7965
+ node-version: 22
7966
+ cache: yarn
7967
+ cache-dependency-path: packages/shared/yarn.lock
7968
+ - run: yarn install --immutable
7969
+ - run: yarn type-check
7970
+ - run: yarn test
7992
7971
  ` : "";
7993
7972
  return `name: CI
7994
7973
 
7995
7974
  on:
7996
7975
  push:
7997
- branches: [main]
7976
+ branches: [master]
7998
7977
  pull_request:
7999
- branches: [main]
7978
+ branches: [master]
8000
7979
 
8001
7980
  concurrency:
8002
7981
  group: \${{ github.workflow }}-\${{ github.ref }}
@@ -8004,94 +7983,41 @@ concurrency:
8004
7983
 
8005
7984
  jobs:
8006
7985
  backend:
8007
- name: Backend (Python)
7986
+ name: "Backend \u2014 lint + test"
8008
7987
  runs-on: ubuntu-latest
8009
7988
  defaults:
8010
7989
  run:
8011
7990
  working-directory: backend
8012
- services:
8013
- postgres:
8014
- image: postgres:16
8015
- env:
8016
- POSTGRES_USER: ci
8017
- POSTGRES_PASSWORD: ci
8018
- POSTGRES_DB: ${projectName.replace(/-/g, "_")}_test
8019
- ports: ["5432:5432"]
8020
- options: >-
8021
- --health-cmd pg_isready
8022
- --health-interval 10s
8023
- --health-timeout 5s
8024
- --health-retries 5
8025
- redis:
8026
- image: redis:7
8027
- ports: ["6379:6379"]
8028
7991
  steps:
8029
7992
  - uses: actions/checkout@v4
8030
7993
  - uses: actions/setup-python@v5
8031
7994
  with:
8032
7995
  python-version: "3.12"
8033
- - run: pip install -e ".[dev,test]"
7996
+ cache: pip
7997
+ cache-dependency-path: backend/requirements*.txt
7998
+ - name: Install dependencies
7999
+ run: |
8000
+ python -m pip install --upgrade pip
8001
+ pip install -r requirements.txt -r requirements-dev.txt
8034
8002
  - run: ruff check .
8035
8003
  - run: ruff format --check .
8036
- - run: pytest --tb=short -q
8037
- ${frontendJob}
8038
- mobile:
8039
- name: Mobile (Expo)
8040
- runs-on: ubuntu-latest
8041
- defaults:
8042
- run:
8043
- working-directory: mobile
8044
- steps:
8045
- - uses: actions/checkout@v4
8046
- - uses: actions/setup-node@v4
8047
- with:
8048
- node-version: 20
8049
- - run: yarn install
8050
- - run: npx tsc --noEmit
8051
- - run: yarn test --ci
8052
-
8053
- shared:
8054
- name: Shared packages
8004
+ - name: Run tests
8005
+ env:
8006
+ DJANGO_SETTINGS_MODULE: config.settings.test
8007
+ SECRET_KEY: ci-test-secret-key-not-for-production
8008
+ CELERY_TASK_ALWAYS_EAGER: "True"
8009
+ run: python -m pytest --tb=short -q
8010
+ ${frontendJob}${mobileJobs}
8011
+ docker:
8012
+ name: "Docker \u2014 smoke build"
8055
8013
  runs-on: ubuntu-latest
8056
- defaults:
8057
- run:
8058
- working-directory: packages/shared
8014
+ needs: ${dockerNeeds}
8015
+ if: github.ref == 'refs/heads/master'
8059
8016
  steps:
8060
8017
  - uses: actions/checkout@v4
8061
- - uses: actions/setup-node@v4
8062
- with:
8063
- node-version: 20
8064
- - run: npx tsc --noEmit
8065
- `;
8066
- }
8067
- function githubDependabot(frontend = true) {
8068
- const frontendUpdate = frontend ? `
8069
- - package-ecosystem: npm
8070
- directory: /frontend
8071
- schedule:
8072
- interval: weekly
8073
- open-pull-requests-limit: 10
8074
- ` : "";
8075
- return `version: 2
8076
- updates:
8077
- - package-ecosystem: pip
8078
- directory: /backend
8079
- schedule:
8080
- interval: weekly
8081
- open-pull-requests-limit: 10
8082
- ${frontendUpdate}
8083
- - package-ecosystem: npm
8084
- directory: /mobile
8085
- schedule:
8086
- interval: weekly
8087
- open-pull-requests-limit: 10
8088
-
8089
- - package-ecosystem: github-actions
8090
- directory: /
8091
- schedule:
8092
- interval: weekly
8093
- open-pull-requests-limit: 5
8094
- `;
8018
+ - name: Build backend image
8019
+ run: docker build -t ${projectName}-be:\${{ github.sha }} ./backend
8020
+ ${frontendDockerStep}`;
8095
8021
  }
8096
8022
 
8097
8023
  // src/commands/app/shared-package.ts
@@ -8110,6 +8036,8 @@ function scaffoldSharedPackage(projectRoot, projectName) {
8110
8036
  mkdirp(import_path14.default.join(sharedRoot, "src", "i18n"));
8111
8037
  writeText(import_path14.default.join(sharedRoot, "package.json"), sharedPackageJson(projectName));
8112
8038
  logOk("package.json");
8039
+ writeText(import_path14.default.join(sharedRoot, ".yarnrc.yml"), "nodeLinker: node-modules\n");
8040
+ logOk(".yarnrc.yml");
8113
8041
  writeText(import_path14.default.join(sharedRoot, "tsconfig.json"), sharedTsconfig());
8114
8042
  logOk("tsconfig.json");
8115
8043
  writeText(import_path14.default.join(sharedRoot, "vitest.config.ts"), sharedVitestConfig());
@@ -8442,10 +8370,14 @@ init_cjs_shims();
8442
8370
  var import_path15 = __toESM(require("path"), 1);
8443
8371
  function patchSharedReferences(projectRoot) {
8444
8372
  logStep("Patching shared package references");
8445
- patchFrontendDockerfile(projectRoot);
8373
+ patchFrontendDocker(projectRoot);
8446
8374
  verifyFrontendSharedAlias(projectRoot);
8447
8375
  verifyMobileSharedPaths(projectRoot);
8448
8376
  }
8377
+ function patchFrontendDocker(projectRoot) {
8378
+ patchFrontendDockerfile(projectRoot);
8379
+ patchFrontendCompose(projectRoot);
8380
+ }
8449
8381
  function patchFrontendDockerfile(projectRoot) {
8450
8382
  const dockerfilePath = import_path15.default.join(projectRoot, "frontend", "Dockerfile");
8451
8383
  if (!exists(dockerfilePath)) {
@@ -8453,30 +8385,102 @@ function patchFrontendDockerfile(projectRoot) {
8453
8385
  return;
8454
8386
  }
8455
8387
  let content = readText(dockerfilePath);
8456
- if (content.includes("COPY packages/shared/")) {
8457
- logOk("Dockerfile \u2014 packages/shared/ COPY already present");
8388
+ if (content.includes("WORKDIR /workspace/packages/shared") && content.includes("COPY packages/shared/") && content.includes("COPY frontend/")) {
8389
+ logOk("Dockerfile \u2014 monorepo shared COPY + install already present");
8458
8390
  return;
8459
8391
  }
8460
- const manifestCopyPatterns = [
8461
- /^(COPY package\.json \.yarnrc\.yml \.\/\n)/m,
8462
- /^(COPY package\.json yarn\.lock \.yarnrc\.yml \.\/\n)/m
8463
- ];
8464
- const matched = manifestCopyPatterns.find((pattern) => pattern.test(content));
8465
- if (matched) {
8466
- content = content.replace(matched, "$1COPY packages/shared/ packages/shared/\n");
8467
- content = content.replace(
8468
- /# Root manifests and lockfile are copied first so `yarn install` is only\n# re-run when dependencies change, not on every source file change\.\n/,
8469
- "# Root manifests, lockfile, and shared packages are copied first so\n# `yarn install` is only re-run when dependencies change.\n"
8470
- );
8392
+ if (content.includes("COPY packages/shared/") && content.includes("WORKDIR /workspace/frontend") && !content.includes("WORKDIR /workspace/packages/shared")) {
8471
8393
  content = content.replace(
8472
- /# Copy dependency files first so dependency installation is cached separately\.\n/,
8473
- "# Copy dependency files and shared packages first so installs cache separately.\n"
8394
+ "WORKDIR /workspace/frontend\nRUN --mount=type=cache,target=/root/.yarn/berry/cache \\\n yarn install --immutable",
8395
+ [
8396
+ "# Shared must have its own node_modules (zod, etc.) \u2014 tsc resolves from source.",
8397
+ "WORKDIR /workspace/packages/shared",
8398
+ "RUN --mount=type=cache,target=/root/.yarn/berry/cache \\",
8399
+ " yarn install --immutable",
8400
+ "",
8401
+ "WORKDIR /workspace/frontend",
8402
+ "RUN --mount=type=cache,target=/root/.yarn/berry/cache \\",
8403
+ " yarn install --immutable"
8404
+ ].join("\n")
8474
8405
  );
8475
8406
  writeText(dockerfilePath, content);
8476
- logOk("Dockerfile \u2014 added COPY packages/shared/ for Docker builds");
8407
+ logOk("Dockerfile \u2014 added packages/shared yarn install for Docker builds");
8408
+ return;
8409
+ }
8410
+ const builderCopy = [
8411
+ "WORKDIR /workspace",
8412
+ "",
8413
+ "RUN corepack enable",
8414
+ "",
8415
+ "COPY packages/shared/ packages/shared/",
8416
+ "COPY frontend/package.json frontend/yarn.lock frontend/.yarnrc.yml frontend/",
8417
+ "",
8418
+ "# Shared must have its own node_modules (zod, etc.) \u2014 tsc resolves from source.",
8419
+ "WORKDIR /workspace/packages/shared",
8420
+ "RUN --mount=type=cache,target=/root/.yarn/berry/cache \\",
8421
+ " yarn install --immutable",
8422
+ "",
8423
+ "WORKDIR /workspace/frontend",
8424
+ "RUN --mount=type=cache,target=/root/.yarn/berry/cache \\",
8425
+ " yarn install --immutable",
8426
+ "",
8427
+ "COPY frontend/ .",
8428
+ "RUN yarn build"
8429
+ ].join("\n");
8430
+ const replaced = content.replace(
8431
+ /WORKDIR \/app[\s\S]*?RUN yarn build/,
8432
+ builderCopy
8433
+ );
8434
+ if (replaced === content) {
8435
+ const replaced2 = content.replace(
8436
+ /# Set working directory\nWORKDIR \/app[\s\S]*?RUN yarn build/,
8437
+ `# Monorepo root is the build context (see docker-compose app-prod).
8438
+ ${builderCopy}`
8439
+ );
8440
+ if (replaced2 === content) {
8441
+ logWarn("Dockerfile \u2014 could not rewrite builder stage; patch skipped");
8442
+ return;
8443
+ }
8444
+ content = replaced2;
8477
8445
  } else {
8478
- logWarn("Dockerfile \u2014 could not locate manifest COPY line; patch skipped");
8446
+ content = replaced;
8447
+ }
8448
+ content = content.replace(
8449
+ /^COPY nginx\.conf /m,
8450
+ "COPY frontend/nginx.conf "
8451
+ );
8452
+ content = content.replace(
8453
+ /^COPY nginx\//m,
8454
+ "COPY frontend/nginx/"
8455
+ );
8456
+ content = content.replace(
8457
+ /COPY --from=builder \/app\/dist /,
8458
+ "COPY --from=builder /workspace/frontend/dist "
8459
+ );
8460
+ writeText(dockerfilePath, content);
8461
+ logOk("Dockerfile \u2014 switched to monorepo root context with packages/shared");
8462
+ }
8463
+ function patchFrontendCompose(projectRoot) {
8464
+ const composePath = import_path15.default.join(projectRoot, "frontend", "docker-compose.yml");
8465
+ if (!exists(composePath)) {
8466
+ logWarn("Frontend docker-compose.yml not found \u2014 skipping compose patch");
8467
+ return;
8479
8468
  }
8469
+ let content = readText(composePath);
8470
+ if (content.includes("context: ..") && content.includes("dockerfile: frontend/Dockerfile")) {
8471
+ logOk("docker-compose.yml \u2014 monorepo build context already set");
8472
+ return;
8473
+ }
8474
+ const next = content.replace(
8475
+ /app-prod:\n(\s+)build:\n\s+context: \.\n\s+dockerfile: Dockerfile/,
8476
+ "app-prod:\n$1build:\n$1 context: ..\n$1 dockerfile: frontend/Dockerfile"
8477
+ );
8478
+ if (next === content) {
8479
+ logWarn("docker-compose.yml \u2014 could not locate app-prod build block; patch skipped");
8480
+ return;
8481
+ }
8482
+ writeText(composePath, next);
8483
+ logOk("docker-compose.yml \u2014 app-prod build context set to repo root");
8480
8484
  }
8481
8485
  function verifyFrontendSharedAlias(projectRoot) {
8482
8486
  const tsconfigPath = import_path15.default.join(projectRoot, "frontend", "tsconfig.json");
@@ -8530,7 +8534,7 @@ function verifyMobileSharedPaths(projectRoot) {
8530
8534
  }
8531
8535
 
8532
8536
  // src/commands/app/index.ts
8533
- var import_fs13 = __toESM(require("fs"), 1);
8537
+ var import_fs14 = __toESM(require("fs"), 1);
8534
8538
 
8535
8539
  // src/commands/app/ai-helpers.ts
8536
8540
  init_cjs_shims();
@@ -8552,7 +8556,7 @@ function getAiHelpersRetryHint(target) {
8552
8556
  const packageJson = require2.resolve(AI_HELPERS_PACKAGE_JSON);
8553
8557
  binPath = import_path16.default.join(import_path16.default.dirname(packageJson), "bin", "cli.mjs");
8554
8558
  } catch {
8555
- return "Install/link the basekit-web workspace dependencies, then re-run create-basekit app with --ai-helpers.";
8559
+ return `Install with \`npm i -D ${AI_HELPERS_PKG}\` (or \`npx ${AI_HELPERS_PKG}\`), then re-run create-basekit app with --ai-helpers.`;
8556
8560
  }
8557
8561
  }
8558
8562
  return `node ${JSON.stringify(binPath)} ${JSON.stringify(target)} --with-claude`;
@@ -8581,7 +8585,7 @@ async function runAppCommand(argv) {
8581
8585
  return;
8582
8586
  }
8583
8587
  if (args.includes("--version") || args.includes("-V")) {
8584
- console.log("1.0.4");
8588
+ console.log("1.0.5");
8585
8589
  return;
8586
8590
  }
8587
8591
  printBanner3();
@@ -8688,7 +8692,7 @@ async function runAppCommand(argv) {
8688
8692
  logError(err instanceof Error ? err.message : String(err));
8689
8693
  if (exists(projectRoot)) {
8690
8694
  try {
8691
- import_fs13.default.rmSync(projectRoot, { recursive: true, force: true });
8695
+ import_fs14.default.rmSync(projectRoot, { recursive: true, force: true });
8692
8696
  logInfo(`Cleaned up ${projectName}/`);
8693
8697
  } catch {
8694
8698
  logError(`Could not clean up ${projectName}/ \u2014 remove it manually before retrying.`);
@@ -8715,12 +8719,12 @@ function initRootGit(projectRoot, includeMobile = false) {
8715
8719
  logInfo("git not found \u2014 skipping repository initialisation");
8716
8720
  return;
8717
8721
  }
8718
- const fs14 = require("fs");
8722
+ const fs15 = require("fs");
8719
8723
  const subDirs = includeMobile ? ["backend", "frontend", "mobile"] : ["backend", "frontend"];
8720
8724
  for (const sub of subDirs) {
8721
8725
  const gitDir = import_path17.default.join(projectRoot, sub, ".git");
8722
8726
  if (exists(gitDir)) {
8723
- fs14.rmSync(gitDir, { recursive: true, force: true });
8727
+ fs15.rmSync(gitDir, { recursive: true, force: true });
8724
8728
  }
8725
8729
  }
8726
8730
  const init = exec("git init", projectRoot);
@@ -8743,7 +8747,7 @@ function initRootGit(projectRoot, includeMobile = false) {
8743
8747
  function printBanner3() {
8744
8748
  console.log("");
8745
8749
  console.log(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
8746
- console.log(` \u2551 create-basekit app v${"1.0.4"} \u2551`);
8750
+ console.log(` \u2551 create-basekit app v${"1.0.5"} \u2551`);
8747
8751
  console.log(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D");
8748
8752
  console.log("");
8749
8753
  console.log(" Full-stack project scaffolder");
@@ -8751,7 +8755,7 @@ function printBanner3() {
8751
8755
  }
8752
8756
  function printHelp3() {
8753
8757
  console.log(`
8754
- create-basekit app v${"1.0.4"}
8758
+ create-basekit app v${"1.0.5"}
8755
8759
 
8756
8760
  Usage: npx @appsbyme/create-basekit app [project-name] [options]
8757
8761