@donotdev/cli 0.0.20 → 0.0.21

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 (103) hide show
  1. package/README.md +31 -0
  2. package/dependencies-matrix.json +86 -19
  3. package/dist/bin/commands/agent-setup.js +2 -2
  4. package/dist/bin/commands/build.js +6 -6
  5. package/dist/bin/commands/bump.js +491 -69
  6. package/dist/bin/commands/cacheout.js +6 -6
  7. package/dist/bin/commands/coach.js +6 -6
  8. package/dist/bin/commands/create-app.js +23 -15
  9. package/dist/bin/commands/create-project.js +101 -16
  10. package/dist/bin/commands/db.js +142136 -0
  11. package/dist/bin/commands/deploy.js +336 -126
  12. package/dist/bin/commands/dev.js +6 -6
  13. package/dist/bin/commands/doctor.js +140 -33
  14. package/dist/bin/commands/emu.js +6 -6
  15. package/dist/bin/commands/format.js +6 -6
  16. package/dist/bin/commands/get-demo.js +11 -6
  17. package/dist/bin/commands/make-admin.js +14210 -13770
  18. package/dist/bin/commands/preview.js +6 -6
  19. package/dist/bin/commands/seed.js +142426 -0
  20. package/dist/bin/commands/setup-cicd.js +8904 -0
  21. package/dist/bin/commands/setup.js +256 -212
  22. package/dist/bin/commands/staging.js +343 -127
  23. package/dist/bin/commands/sync-secrets.js +55 -33
  24. package/dist/bin/commands/type-check.js +6 -6
  25. package/dist/bin/commands/wai.js +6 -6
  26. package/dist/bin/dndev.js +76 -11
  27. package/dist/bin/donotdev.js +21 -12
  28. package/dist/index.js +437 -142
  29. package/package.json +1 -1
  30. package/templates/app-demo/.env.example +1 -0
  31. package/templates/{root-consumer → app-demo}/entities/ExampleEntity.ts.example +15 -9
  32. package/templates/app-demo/index.html.example +1 -1
  33. package/templates/app-dndev/index.html.example +164 -0
  34. package/templates/app-dndev/public/logo.svg.example +1 -0
  35. package/templates/app-dndev/public/manifest.json.example +10 -0
  36. package/templates/app-dndev/src/App.tsx.example +35 -0
  37. package/templates/app-dndev/src/components/CockpitLayout.css.example +181 -0
  38. package/templates/app-dndev/src/components/CockpitLayout.tsx.example +209 -0
  39. package/templates/app-dndev/src/components/Kanban.css.example +385 -0
  40. package/templates/app-dndev/src/components/ModeToggle.tsx.example +32 -0
  41. package/templates/app-dndev/src/components/OverlaySlot.tsx.example +68 -0
  42. package/templates/app-dndev/src/components/TerminalPanel.css.example +228 -0
  43. package/templates/app-dndev/src/components/TerminalPanel.tsx.example +714 -0
  44. package/templates/app-dndev/src/components/markdown-prose.css.example +49 -0
  45. package/templates/app-dndev/src/components/phases/CaptainLog.tsx.example +107 -0
  46. package/templates/app-dndev/src/components/phases/ContextTabs.tsx.example +352 -0
  47. package/templates/app-dndev/src/components/phases/PhaseCard.tsx.example +126 -0
  48. package/templates/app-dndev/src/components/phases/PhaseDetail.tsx.example +147 -0
  49. package/templates/app-dndev/src/components/phases/ReviewPanel.tsx.example +115 -0
  50. package/templates/app-dndev/src/components/phases/phaseData.ts.example +366 -0
  51. package/templates/app-dndev/src/config/app.ts.example +103 -0
  52. package/templates/app-dndev/src/config/commands.ts.example +171 -0
  53. package/templates/app-dndev/src/config/legal.ts.example +170 -0
  54. package/templates/app-dndev/src/config/providers.ts.example +7 -0
  55. package/templates/app-dndev/src/globals.css.example +10 -0
  56. package/templates/app-dndev/src/hooks/useDndevFile.ts.example +144 -0
  57. package/templates/app-dndev/src/main.tsx.example +21 -0
  58. package/templates/app-dndev/src/pages/BoardPage.tsx.example +640 -0
  59. package/templates/app-dndev/src/pages/GrillPage.tsx.example +658 -0
  60. package/templates/app-dndev/src/pages/HomePage.tsx.example +347 -0
  61. package/templates/app-dndev/src/pages/NotFoundPage.tsx.example +33 -0
  62. package/templates/app-dndev/src/pages/PhasesPage.tsx.example +137 -0
  63. package/templates/app-dndev/src/pages/SettingsPage.tsx.example +64 -0
  64. package/templates/app-dndev/src/pages/legal/LegalNoticePage.tsx.example +75 -0
  65. package/templates/app-dndev/src/pages/legal/PrivacyPage.tsx.example +69 -0
  66. package/templates/app-dndev/src/pages/legal/TermsPage.tsx.example +71 -0
  67. package/templates/app-dndev/src/stores/dndevStore.ts.example +386 -0
  68. package/templates/app-dndev/src/themes.css.example +161 -0
  69. package/templates/app-dndev/terminal-sidecar.cjs.example +341 -0
  70. package/templates/app-dndev/tsconfig.json.example +9 -0
  71. package/templates/app-dndev/vite.config.ts.example +24 -0
  72. package/templates/app-next/src/locales/home_en.json.example +6 -6
  73. package/templates/app-vite/index.html.example +1 -1
  74. package/templates/app-vite/src/locales/home_en.json.example +6 -6
  75. package/templates/functions-supabase/supabase/functions/.env.example +0 -2
  76. package/templates/root-consumer/.claude/commands/grill.md.example +86 -8
  77. package/templates/root-consumer/.dndev.secrets.example +32 -0
  78. package/templates/root-consumer/.gitignore.example +3 -0
  79. package/templates/root-consumer/AI.md.example +4 -0
  80. package/templates/root-consumer/entities/index.ts.example +2 -5
  81. package/templates/root-consumer/guides/dndev/COMPONENTS_ATOMIC.md.example +4 -0
  82. package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +23 -20
  83. package/templates/root-consumer/guides/dndev/INDEX.md.example +1 -0
  84. package/templates/root-consumer/guides/dndev/SETUP_BILLING.md.example +3 -7
  85. package/templates/root-consumer/guides/dndev/SETUP_CICD.md.example +115 -0
  86. package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +41 -0
  87. package/templates/root-consumer/guides/dndev/SETUP_SUPABASE.md.example +13 -18
  88. package/templates/root-consumer/guides/dndev/SETUP_VERCEL.md.example +17 -12
  89. package/templates/root-consumer/guides/dndev/advanced/COOKIE_REFERENCE.md.example +252 -252
  90. package/templates/root-consumer/guides/dndev/advanced/VERSION_CONTROL.md.example +174 -174
  91. package/templates/root-consumer/guides/wai-way/WAI_WAY_CLI.md.example +185 -251
  92. package/templates/root-consumer/guides/wai-way/agents/extractor.md.example +26 -8
  93. package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +66 -49
  94. package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +6 -5
  95. package/templates/root-consumer/guides/wai-way/blueprints/2_entities.md.example +9 -9
  96. package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +1 -1
  97. package/templates/root-consumer/guides/wai-way/blueprints/4_configure.md.example +7 -6
  98. package/templates/root-consumer/guides/wai-way/context_map.json.example +51 -20
  99. package/templates/root-consumer/guides/wai-way/hld_template.md.example +138 -0
  100. package/templates/root-consumer/guides/wai-way/lld_template.md.example +103 -0
  101. package/templates/root-consumer/guides/wai-way/prd_template.md.example +140 -0
  102. /package/templates/{root-consumer → app-demo}/entities/Contact.ts.example +0 -0
  103. /package/templates/{root-consumer → app-demo}/entities/demo.ts.example +0 -0
package/dist/index.js CHANGED
@@ -3351,9 +3351,9 @@ var require_parse2 = __commonJS({
3351
3351
  const idx = prev.value.lastIndexOf("[");
3352
3352
  const pre = prev.value.slice(0, idx);
3353
3353
  const rest2 = prev.value.slice(idx + 2);
3354
- const posix = POSIX_REGEX_SOURCE[rest2];
3355
- if (posix) {
3356
- prev.value = pre + posix;
3354
+ const posix2 = POSIX_REGEX_SOURCE[rest2];
3355
+ if (posix2) {
3356
+ prev.value = pre + posix2;
3357
3357
  state.backtrack = true;
3358
3358
  advance();
3359
3359
  if (!bos.output && tokens.indexOf(prev) === 1) {
@@ -3875,7 +3875,7 @@ var require_picomatch = __commonJS({
3875
3875
  throw new TypeError("Expected pattern to be a non-empty string");
3876
3876
  }
3877
3877
  const opts = options || {};
3878
- const posix = utils.isWindows(options);
3878
+ const posix2 = utils.isWindows(options);
3879
3879
  const regex = isState ? picomatch.compileRe(glob2, options) : picomatch.makeRe(glob2, options, false, true);
3880
3880
  const state = regex.state;
3881
3881
  delete regex.state;
@@ -3885,8 +3885,8 @@ var require_picomatch = __commonJS({
3885
3885
  isIgnored = picomatch(opts.ignore, ignoreOpts, returnState);
3886
3886
  }
3887
3887
  const matcher = (input, returnObject = false) => {
3888
- const { isMatch, match, output } = picomatch.test(input, regex, options, { glob: glob2, posix });
3889
- const result = { glob: glob2, state, regex, posix, input, output, match, isMatch };
3888
+ const { isMatch, match, output } = picomatch.test(input, regex, options, { glob: glob2, posix: posix2 });
3889
+ const result = { glob: glob2, state, regex, posix: posix2, input, output, match, isMatch };
3890
3890
  if (typeof opts.onResult === "function") {
3891
3891
  opts.onResult(result);
3892
3892
  }
@@ -3911,7 +3911,7 @@ var require_picomatch = __commonJS({
3911
3911
  }
3912
3912
  return matcher;
3913
3913
  };
3914
- picomatch.test = (input, regex, options, { glob: glob2, posix } = {}) => {
3914
+ picomatch.test = (input, regex, options, { glob: glob2, posix: posix2 } = {}) => {
3915
3915
  if (typeof input !== "string") {
3916
3916
  throw new TypeError("Expected input to be a string");
3917
3917
  }
@@ -3919,7 +3919,7 @@ var require_picomatch = __commonJS({
3919
3919
  return { isMatch: false, output: "" };
3920
3920
  }
3921
3921
  const opts = options || {};
3922
- const format = opts.format || (posix ? utils.toPosixSlashes : null);
3922
+ const format = opts.format || (posix2 ? utils.toPosixSlashes : null);
3923
3923
  let match = input === glob2;
3924
3924
  let output = match && format ? format(input) : input;
3925
3925
  if (match === false) {
@@ -3928,14 +3928,14 @@ var require_picomatch = __commonJS({
3928
3928
  }
3929
3929
  if (match === false || opts.capture === true) {
3930
3930
  if (opts.matchBase === true || opts.basename === true) {
3931
- match = picomatch.matchBase(input, regex, options, posix);
3931
+ match = picomatch.matchBase(input, regex, options, posix2);
3932
3932
  } else {
3933
3933
  match = regex.exec(output);
3934
3934
  }
3935
3935
  }
3936
3936
  return { isMatch: Boolean(match), match, output };
3937
3937
  };
3938
- picomatch.matchBase = (input, glob2, options, posix = utils.isWindows(options)) => {
3938
+ picomatch.matchBase = (input, glob2, options, posix2 = utils.isWindows(options)) => {
3939
3939
  const regex = glob2 instanceof RegExp ? glob2 : picomatch.makeRe(glob2, options);
3940
3940
  return regex.test(path.basename(input));
3941
3941
  };
@@ -4126,9 +4126,9 @@ var require_micromatch = __commonJS({
4126
4126
  return [].concat(patterns).every((p2) => picomatch(p2, options)(str));
4127
4127
  };
4128
4128
  micromatch.capture = (glob2, input, options) => {
4129
- let posix = utils.isWindows(options);
4129
+ let posix2 = utils.isWindows(options);
4130
4130
  let regex = picomatch.makeRe(String(glob2), { ...options, capture: true });
4131
- let match = regex.exec(posix ? utils.toPosixSlashes(input) : input);
4131
+ let match = regex.exec(posix2 ? utils.toPosixSlashes(input) : input);
4132
4132
  if (match) {
4133
4133
  return match.slice(1).map((v2) => v2 === void 0 ? "" : v2);
4134
4134
  }
@@ -4308,15 +4308,15 @@ var require_pattern = __commonJS({
4308
4308
  exports.removeDuplicateSlashes = removeDuplicateSlashes;
4309
4309
  function partitionAbsoluteAndRelative(patterns) {
4310
4310
  const absolute = [];
4311
- const relative3 = [];
4311
+ const relative4 = [];
4312
4312
  for (const pattern of patterns) {
4313
4313
  if (isAbsolute2(pattern)) {
4314
4314
  absolute.push(pattern);
4315
4315
  } else {
4316
- relative3.push(pattern);
4316
+ relative4.push(pattern);
4317
4317
  }
4318
4318
  }
4319
- return [absolute, relative3];
4319
+ return [absolute, relative4];
4320
4320
  }
4321
4321
  exports.partitionAbsoluteAndRelative = partitionAbsoluteAndRelative;
4322
4322
  function isAbsolute2(pattern) {
@@ -4626,7 +4626,7 @@ var require_async = __commonJS({
4626
4626
  callSuccessCallback(callback, lstat);
4627
4627
  return;
4628
4628
  }
4629
- settings.fs.stat(path, (statError, stat) => {
4629
+ settings.fs.stat(path, (statError, stat2) => {
4630
4630
  if (statError !== null) {
4631
4631
  if (settings.throwErrorOnBrokenSymbolicLink) {
4632
4632
  callFailureCallback(callback, statError);
@@ -4636,9 +4636,9 @@ var require_async = __commonJS({
4636
4636
  return;
4637
4637
  }
4638
4638
  if (settings.markSymbolicLink) {
4639
- stat.isSymbolicLink = () => true;
4639
+ stat2.isSymbolicLink = () => true;
4640
4640
  }
4641
- callSuccessCallback(callback, stat);
4641
+ callSuccessCallback(callback, stat2);
4642
4642
  });
4643
4643
  });
4644
4644
  }
@@ -4665,11 +4665,11 @@ var require_sync = __commonJS({
4665
4665
  return lstat;
4666
4666
  }
4667
4667
  try {
4668
- const stat = settings.fs.statSync(path);
4668
+ const stat2 = settings.fs.statSync(path);
4669
4669
  if (settings.markSymbolicLink) {
4670
- stat.isSymbolicLink = () => true;
4670
+ stat2.isSymbolicLink = () => true;
4671
4671
  }
4672
- return stat;
4672
+ return stat2;
4673
4673
  } catch (error2) {
4674
4674
  if (!settings.throwErrorOnBrokenSymbolicLink) {
4675
4675
  return lstat;
@@ -4739,14 +4739,14 @@ var require_out = __commonJS({
4739
4739
  var sync = require_sync();
4740
4740
  var settings_1 = require_settings();
4741
4741
  exports.Settings = settings_1.default;
4742
- function stat(path, optionsOrSettingsOrCallback, callback) {
4742
+ function stat2(path, optionsOrSettingsOrCallback, callback) {
4743
4743
  if (typeof optionsOrSettingsOrCallback === "function") {
4744
4744
  async.read(path, getSettings(), optionsOrSettingsOrCallback);
4745
4745
  return;
4746
4746
  }
4747
4747
  async.read(path, getSettings(optionsOrSettingsOrCallback), callback);
4748
4748
  }
4749
- exports.stat = stat;
4749
+ exports.stat = stat2;
4750
4750
  function statSync3(path, optionsOrSettings) {
4751
4751
  const settings = getSettings(optionsOrSettings);
4752
4752
  return sync.read(path, settings);
@@ -4916,7 +4916,7 @@ var require_async2 = __commonJS({
4916
4916
  readdirWithFileTypes(directory, settings, callback);
4917
4917
  return;
4918
4918
  }
4919
- readdir2(directory, settings, callback);
4919
+ readdir3(directory, settings, callback);
4920
4920
  }
4921
4921
  exports.read = read2;
4922
4922
  function readdirWithFileTypes(directory, settings, callback) {
@@ -4965,7 +4965,7 @@ var require_async2 = __commonJS({
4965
4965
  });
4966
4966
  };
4967
4967
  }
4968
- function readdir2(directory, settings, callback) {
4968
+ function readdir3(directory, settings, callback) {
4969
4969
  settings.fs.readdir(directory, (readdirError, names) => {
4970
4970
  if (readdirError !== null) {
4971
4971
  callFailureCallback(callback, readdirError);
@@ -5000,7 +5000,7 @@ var require_async2 = __commonJS({
5000
5000
  });
5001
5001
  });
5002
5002
  }
5003
- exports.readdir = readdir2;
5003
+ exports.readdir = readdir3;
5004
5004
  function callFailureCallback(callback, error2) {
5005
5005
  callback(error2);
5006
5006
  }
@@ -5025,7 +5025,7 @@ var require_sync2 = __commonJS({
5025
5025
  if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) {
5026
5026
  return readdirWithFileTypes(directory, settings);
5027
5027
  }
5028
- return readdir2(directory, settings);
5028
+ return readdir3(directory, settings);
5029
5029
  }
5030
5030
  exports.read = read2;
5031
5031
  function readdirWithFileTypes(directory, settings) {
@@ -5050,7 +5050,7 @@ var require_sync2 = __commonJS({
5050
5050
  });
5051
5051
  }
5052
5052
  exports.readdirWithFileTypes = readdirWithFileTypes;
5053
- function readdir2(directory, settings) {
5053
+ function readdir3(directory, settings) {
5054
5054
  const names = settings.fs.readdirSync(directory);
5055
5055
  return names.map((name) => {
5056
5056
  const entryPath = common.joinPathSegments(directory, name, settings.pathSegmentSeparator);
@@ -5066,7 +5066,7 @@ var require_sync2 = __commonJS({
5066
5066
  return entry;
5067
5067
  });
5068
5068
  }
5069
- exports.readdir = readdir2;
5069
+ exports.readdir = readdir3;
5070
5070
  }
5071
5071
  });
5072
5072
 
@@ -6628,19 +6628,19 @@ var require_out4 = __commonJS({
6628
6628
  return utils.path.convertPathToPattern(source);
6629
6629
  }
6630
6630
  FastGlob2.convertPathToPattern = convertPathToPattern;
6631
- let posix;
6632
- (function(posix2) {
6631
+ let posix2;
6632
+ (function(posix3) {
6633
6633
  function escapePath2(source) {
6634
6634
  assertPatternsInput(source);
6635
6635
  return utils.path.escapePosixPath(source);
6636
6636
  }
6637
- posix2.escapePath = escapePath2;
6637
+ posix3.escapePath = escapePath2;
6638
6638
  function convertPathToPattern2(source) {
6639
6639
  assertPatternsInput(source);
6640
6640
  return utils.path.convertPosixPathToPattern(source);
6641
6641
  }
6642
- posix2.convertPathToPattern = convertPathToPattern2;
6643
- })(posix = FastGlob2.posix || (FastGlob2.posix = {}));
6642
+ posix3.convertPathToPattern = convertPathToPattern2;
6643
+ })(posix2 = FastGlob2.posix || (FastGlob2.posix = {}));
6644
6644
  let win32;
6645
6645
  (function(win322) {
6646
6646
  function escapePath2(source) {
@@ -7219,7 +7219,7 @@ var init_PathResolver = __esm({
7219
7219
  }
7220
7220
  const detectedFormat = this._detectFormat(filePath, format);
7221
7221
  let writeContent;
7222
- if (Buffer2.isBuffer(content)) {
7222
+ if (Buffer.isBuffer(content)) {
7223
7223
  writeContent = content;
7224
7224
  } else if (detectedFormat === "json" && typeof content === "object") {
7225
7225
  writeContent = JSON.stringify(content, null, 2);
@@ -7228,7 +7228,7 @@ var init_PathResolver = __esm({
7228
7228
  }
7229
7229
  try {
7230
7230
  return await safeExecuteAsync(async () => {
7231
- if (Buffer2.isBuffer(writeContent)) {
7231
+ if (Buffer.isBuffer(writeContent)) {
7232
7232
  await fs.promises.writeFile(normalizedPath, writeContent);
7233
7233
  } else {
7234
7234
  await fs.promises.writeFile(normalizedPath, writeContent, "utf8");
@@ -7280,7 +7280,7 @@ var init_PathResolver = __esm({
7280
7280
  }
7281
7281
  const detectedFormat = this._detectFormat(filePath, format);
7282
7282
  let writeContent;
7283
- if (Buffer2.isBuffer(content)) {
7283
+ if (Buffer.isBuffer(content)) {
7284
7284
  writeContent = content;
7285
7285
  } else if (detectedFormat === "json" && typeof content === "object") {
7286
7286
  writeContent = JSON.stringify(content, null, 2);
@@ -7288,7 +7288,7 @@ var init_PathResolver = __esm({
7288
7288
  writeContent = String(content);
7289
7289
  }
7290
7290
  try {
7291
- if (Buffer2.isBuffer(writeContent)) {
7291
+ if (Buffer.isBuffer(writeContent)) {
7292
7292
  fs.writeFileSync(normalizedPath, writeContent);
7293
7293
  } else {
7294
7294
  fs.writeFileSync(normalizedPath, writeContent, "utf8");
@@ -8181,7 +8181,7 @@ async function isBinaryFile(filePath) {
8181
8181
  try {
8182
8182
  let fileHandle = null;
8183
8183
  try {
8184
- const buffer = Buffer2.alloc(4096);
8184
+ const buffer = Buffer.alloc(4096);
8185
8185
  const fs2 = await import("node:fs");
8186
8186
  fileHandle = await fs2.promises.open(filePath, "r");
8187
8187
  const { bytesRead } = await fileHandle.read(buffer, 0, 4096, 0);
@@ -8359,8 +8359,8 @@ var init_pathResolver = __esm({
8359
8359
  if (normalizedTarget === normalizedRoot) {
8360
8360
  return true;
8361
8361
  }
8362
- const relative3 = getRelativePathBetween(normalizedRoot, normalizedTarget);
8363
- return Boolean(relative3) && !relative3.startsWith("../") && !relative3.startsWith("/") && !relative3.includes("..");
8362
+ const relative4 = getRelativePathBetween(normalizedRoot, normalizedTarget);
8363
+ return Boolean(relative4) && !relative4.startsWith("../") && !relative4.startsWith("/") && !relative4.includes("..");
8364
8364
  };
8365
8365
  }
8366
8366
  });
@@ -8491,7 +8491,7 @@ var init_typed_file_operations = __esm({
8491
8491
  });
8492
8492
 
8493
8493
  // packages/tooling/src/bundler/utils.ts
8494
- import { Buffer as Buffer2 } from "node:buffer";
8494
+ import { Buffer } from "node:buffer";
8495
8495
  import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
8496
8496
  import { createRequire as createRequire3 } from "node:module";
8497
8497
  import { dirname as dirname3, resolve as resolve3 } from "node:path";
@@ -8508,7 +8508,7 @@ var init_utils = __esm({
8508
8508
  globalThis.require = require2;
8509
8509
  globalThis.__filename = __filename;
8510
8510
  globalThis.__dirname = __dirname;
8511
- globalThis.Buffer = Buffer2;
8511
+ globalThis.Buffer = Buffer;
8512
8512
  globalThis.process = process;
8513
8513
  if (typeof global === "undefined") {
8514
8514
  globalThis.global = globalThis;
@@ -9016,7 +9016,28 @@ var init_cli_tools = __esm({
9016
9016
  }
9017
9017
  });
9018
9018
 
9019
- // packages/tooling/src/cli/setup/vercel-token.ts
9019
+ // packages/tooling/src/utils/secrets-resolver.ts
9020
+ function parseEnvFile(filePath) {
9021
+ if (!pathExists(filePath)) return {};
9022
+ const content = readSync(filePath, { format: "text" });
9023
+ if (typeof content !== "string" || !content) return {};
9024
+ const result = {};
9025
+ for (const line of content.split(/\r?\n/)) {
9026
+ const trimmed = line.trim();
9027
+ if (!trimmed || trimmed.startsWith("#")) continue;
9028
+ const eqIdx = trimmed.indexOf("=");
9029
+ if (eqIdx === -1) continue;
9030
+ const key = trimmed.slice(0, eqIdx).trim();
9031
+ let value = trimmed.slice(eqIdx + 1).trim();
9032
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
9033
+ value = value.slice(1, -1);
9034
+ }
9035
+ if (key && value) {
9036
+ result[key] = value;
9037
+ }
9038
+ }
9039
+ return result;
9040
+ }
9020
9041
  function readEnvVar(filePath, varName) {
9021
9042
  if (!pathExists(filePath)) return null;
9022
9043
  const content = readSync(filePath, { format: "text" });
@@ -9025,16 +9046,93 @@ function readEnvVar(filePath, varName) {
9025
9046
  const trimmed = line.trim();
9026
9047
  if (!trimmed || trimmed.startsWith("#")) continue;
9027
9048
  if (trimmed.startsWith(`${varName}=`)) {
9028
- const val = trimmed.substring(`${varName}=`.length).trim();
9049
+ let val = trimmed.substring(`${varName}=`.length).trim();
9029
9050
  if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
9030
- return val.slice(1, -1);
9051
+ val = val.slice(1, -1);
9031
9052
  }
9032
9053
  return val || null;
9033
9054
  }
9034
9055
  }
9035
9056
  return null;
9036
9057
  }
9037
- function resolveVercelVar(appDir, varName) {
9058
+ function loadDndevSecrets(projectRoot) {
9059
+ const secretsPath = joinPath(projectRoot, ".dndev.secrets");
9060
+ if (cachedSecretsPath === secretsPath && cachedSecrets) {
9061
+ return cachedSecrets;
9062
+ }
9063
+ cachedSecrets = parseEnvFile(secretsPath);
9064
+ cachedSecretsPath = secretsPath;
9065
+ return cachedSecrets;
9066
+ }
9067
+ function resolveSecret(name, projectRoot, opts) {
9068
+ const appDir = opts?.appDir ?? projectRoot;
9069
+ const envValue = process.env[name];
9070
+ if (envValue) {
9071
+ return { value: envValue, source: "process.env" };
9072
+ }
9073
+ const secrets = loadDndevSecrets(projectRoot);
9074
+ if (secrets[name]) {
9075
+ return { value: secrets[name], source: ".dndev.secrets" };
9076
+ }
9077
+ if (name === "SUPABASE_SECRET_KEY" && secrets["SUPABASE_SERVICE_ROLE_KEY"]) {
9078
+ return {
9079
+ value: secrets["SUPABASE_SERVICE_ROLE_KEY"],
9080
+ source: ".dndev.secrets"
9081
+ };
9082
+ }
9083
+ const legacyPaths = LEGACY_PATHS[name];
9084
+ if (legacyPaths) {
9085
+ for (const relPath of legacyPaths) {
9086
+ const fullPath = joinPath(appDir, relPath);
9087
+ const value = readEnvVar(fullPath, name);
9088
+ if (value) {
9089
+ if (!opts?.silent && !warnedLegacy.has(name)) {
9090
+ warnedLegacy.add(name);
9091
+ log.warn(
9092
+ `${name} found in ${relPath} (legacy). Move it to .dndev.secrets at project root.`
9093
+ );
9094
+ }
9095
+ return { value, source: "legacy", legacyPath: relPath };
9096
+ }
9097
+ if (name === "SUPABASE_SECRET_KEY") {
9098
+ const aliasValue = readEnvVar(fullPath, "SUPABASE_SERVICE_ROLE_KEY");
9099
+ if (aliasValue) {
9100
+ if (!opts?.silent && !warnedLegacy.has(name)) {
9101
+ warnedLegacy.add(name);
9102
+ log.warn(
9103
+ `${name} found in ${relPath} (legacy). Move it to .dndev.secrets at project root.`
9104
+ );
9105
+ }
9106
+ return { value: aliasValue, source: "legacy", legacyPath: relPath };
9107
+ }
9108
+ }
9109
+ }
9110
+ }
9111
+ return null;
9112
+ }
9113
+ var LEGACY_PATHS, warnedLegacy, cachedSecretsPath, cachedSecrets;
9114
+ var init_secrets_resolver = __esm({
9115
+ "packages/tooling/src/utils/secrets-resolver.ts"() {
9116
+ "use strict";
9117
+ init_utils();
9118
+ init_pathResolver();
9119
+ init_cli_output();
9120
+ LEGACY_PATHS = {
9121
+ VERCEL_TOKEN: [".env.local"],
9122
+ SUPABASE_SECRET_KEY: ["supabase/functions/.env", "functions/.env"],
9123
+ SUPABASE_DB_URL: ["supabase/functions/.env", "functions/.env"],
9124
+ SUPABASE_ACCESS_TOKEN: ["supabase/functions/.env", "functions/.env"],
9125
+ STRIPE_SECRET_KEY: ["supabase/functions/.env", "functions/.env"],
9126
+ STRIPE_WEBHOOK_SECRET: ["supabase/functions/.env", "functions/.env"]
9127
+ };
9128
+ warnedLegacy = /* @__PURE__ */ new Set();
9129
+ cachedSecretsPath = null;
9130
+ cachedSecrets = null;
9131
+ }
9132
+ });
9133
+
9134
+ // packages/tooling/src/cli/setup/vercel-token.ts
9135
+ function resolvePerAppVar(appDir, varName) {
9038
9136
  if (process.env[varName]) return process.env[varName];
9039
9137
  const fromLocal = readEnvVar(joinPath(appDir, ".env.local"), varName);
9040
9138
  if (fromLocal) return fromLocal;
@@ -9042,10 +9140,11 @@ function resolveVercelVar(appDir, varName) {
9042
9140
  if (fromEnv) return fromEnv;
9043
9141
  return null;
9044
9142
  }
9045
- function resolveVercelCredentials(appDir) {
9046
- const token = resolveVercelVar(appDir, "VERCEL_TOKEN");
9047
- const orgId = resolveVercelVar(appDir, "VERCEL_ORG_ID");
9048
- const projectId = resolveVercelVar(appDir, "VERCEL_PROJECT_ID");
9143
+ function resolveVercelCredentials(appDir, projectRoot) {
9144
+ const root = projectRoot ?? process.cwd();
9145
+ const token = resolveSecret("VERCEL_TOKEN", root, { appDir })?.value ?? null;
9146
+ const orgId = resolvePerAppVar(appDir, "VERCEL_ORG_ID");
9147
+ const projectId = resolvePerAppVar(appDir, "VERCEL_PROJECT_ID");
9049
9148
  const missing = [];
9050
9149
  if (!token) missing.push("VERCEL_TOKEN");
9051
9150
  if (!orgId) missing.push("VERCEL_ORG_ID");
@@ -9059,6 +9158,7 @@ var init_vercel_token = __esm({
9059
9158
  "packages/tooling/src/cli/setup/vercel-token.ts"() {
9060
9159
  "use strict";
9061
9160
  init_utils();
9161
+ init_secrets_resolver();
9062
9162
  init_pathResolver();
9063
9163
  }
9064
9164
  });
@@ -16451,10 +16551,14 @@ var init_error_handling = __esm({
16451
16551
  var sync_secrets_exports = {};
16452
16552
  __export(sync_secrets_exports, {
16453
16553
  default: () => sync_secrets_default,
16454
- main: () => main5
16554
+ detectGitHubRepo: () => detectGitHubRepo,
16555
+ main: () => main5,
16556
+ parseSecretsWithFallback: () => parseSecretsWithFallback,
16557
+ setGitHubSecret: () => setGitHubSecret,
16558
+ uploadServiceAccountToGitHub: () => uploadServiceAccountToGitHub
16455
16559
  });
16456
- import { spawnSync as spawnSync9 } from "node:child_process";
16457
- function parseEnvFile(filePath) {
16560
+ import { spawnSync as spawnSync8 } from "node:child_process";
16561
+ function parseEnvFile2(filePath) {
16458
16562
  if (!pathExists(filePath)) {
16459
16563
  throw new DoNotDevError(
16460
16564
  `Environment file not found: ${filePath}`,
@@ -16462,30 +16566,22 @@ function parseEnvFile(filePath) {
16462
16566
  { context: { filePath } }
16463
16567
  );
16464
16568
  }
16465
- const contentRaw = readSync(filePath, { format: "text" });
16466
- const content = typeof contentRaw === "string" ? contentRaw : null;
16467
- if (!content) {
16468
- throw new Error(`Failed to read secrets file: ${filePath}`);
16569
+ const result = parseEnvFile(filePath);
16570
+ if (Object.keys(result).length === 0) {
16571
+ log.debug(`No key-value pairs found in ${filePath}`);
16469
16572
  }
16470
- const secrets = {};
16471
- content.split("\n").forEach((line, index) => {
16472
- const trimmedLine = line.trim();
16473
- if (!trimmedLine || trimmedLine.startsWith("#")) {
16474
- return;
16475
- }
16476
- const equalIndex = trimmedLine.indexOf("=");
16477
- if (equalIndex === -1) {
16478
- log.warn(`Invalid line format at line ${index + 1}: ${trimmedLine}`);
16479
- return;
16480
- }
16481
- const key = trimmedLine.substring(0, equalIndex).trim();
16482
- const value = trimmedLine.substring(equalIndex + 1).trim();
16483
- const cleanValue = value.replace(/^["']|["']$/g, "");
16484
- if (key && cleanValue) {
16485
- secrets[key] = cleanValue;
16573
+ return result;
16574
+ }
16575
+ function parseSecretsWithFallback(envFilePath, projectRoot) {
16576
+ const dndevSecretsPath = joinPath(projectRoot, ".dndev.secrets");
16577
+ if (pathExists(dndevSecretsPath)) {
16578
+ const secrets = parseEnvFile(dndevSecretsPath);
16579
+ if (Object.keys(secrets).length > 0) {
16580
+ log.info(`Reading secrets from: ${dndevSecretsPath}`);
16581
+ return secrets;
16486
16582
  }
16487
- });
16488
- return secrets;
16583
+ }
16584
+ return parseEnvFile2(envFilePath);
16489
16585
  }
16490
16586
  function detectPlatform() {
16491
16587
  const currentDir = process.cwd();
@@ -16576,8 +16672,8 @@ function detectAppsWithFunctions() {
16576
16672
  try {
16577
16673
  const appsList = readdirSync2(appsDir).filter((item) => {
16578
16674
  const itemPath = joinPath(appsDir, item);
16579
- const stat = statSync2(itemPath);
16580
- return stat?.isDirectory() === true;
16675
+ const stat2 = statSync2(itemPath);
16676
+ return stat2?.isDirectory() === true;
16581
16677
  });
16582
16678
  for (const app of appsList) {
16583
16679
  const functionsEnvFile = joinPath(appsDir, app, "functions", ".env");
@@ -16643,7 +16739,7 @@ async function setFirebaseSecret(key, value, projectId, dryRun = false, cwd) {
16643
16739
  NODE_OPTIONS: ""
16644
16740
  // Clear to avoid conflicts
16645
16741
  };
16646
- const result = spawnSync9(firebaseCmd, args, {
16742
+ const result = spawnSync8(firebaseCmd, args, {
16647
16743
  input: value,
16648
16744
  encoding: "utf8",
16649
16745
  stdio: ["pipe", "pipe", "pipe"],
@@ -16736,7 +16832,7 @@ function setVercelSecret(key, value, projectId, dryRun = false) {
16736
16832
  if (projectId) {
16737
16833
  args.push("--project", projectId);
16738
16834
  }
16739
- const result = spawnSync9("vercel", args, {
16835
+ const result = spawnSync8("vercel", args, {
16740
16836
  input: value,
16741
16837
  encoding: "utf8",
16742
16838
  stdio: ["pipe", "inherit", "inherit"]
@@ -16765,7 +16861,7 @@ function setVercelSecret(key, value, projectId, dryRun = false) {
16765
16861
  }
16766
16862
  function detectGitHubRepo() {
16767
16863
  try {
16768
- const result = spawnSync9("git", ["remote", "get-url", "origin"], {
16864
+ const result = spawnSync8("git", ["remote", "get-url", "origin"], {
16769
16865
  encoding: "utf8",
16770
16866
  stdio: ["pipe", "pipe", "pipe"]
16771
16867
  });
@@ -16793,7 +16889,7 @@ function setGitHubSecret(key, value, repo, dryRun = false) {
16793
16889
  if (repo) {
16794
16890
  args.push("--repo", repo);
16795
16891
  }
16796
- const result = spawnSync9("gh", args, {
16892
+ const result = spawnSync8("gh", args, {
16797
16893
  input: value,
16798
16894
  encoding: "utf8",
16799
16895
  stdio: ["pipe", "pipe", "pipe"]
@@ -16845,7 +16941,7 @@ function uploadServiceAccountToGitHub(appDir, repo, dryRun = false, staging = fa
16845
16941
  const contentRaw = readSync(filePath, { format: "text" });
16846
16942
  const content = typeof contentRaw === "string" ? contentRaw : null;
16847
16943
  if (!content) return;
16848
- const encoded = Buffer2.from(content).toString("base64");
16944
+ const encoded = Buffer.from(content).toString("base64");
16849
16945
  setGitHubSecret(secretName, encoded, repo, dryRun);
16850
16946
  }
16851
16947
  async function main5(options = {}) {
@@ -16932,7 +17028,7 @@ Examples:
16932
17028
  return 1;
16933
17029
  }
16934
17030
  log.info(`Syncing secrets to GitHub repository: ${repo}`);
16935
- const secrets2 = parseEnvFile(envFilePath);
17031
+ const secrets2 = parseSecretsWithFallback(envFilePath, currentDir);
16936
17032
  const secretKeys2 = Object.keys(secrets2);
16937
17033
  if (secretKeys2.length === 0) {
16938
17034
  log.info("No secrets found in .env file");
@@ -16968,14 +17064,13 @@ Examples:
16968
17064
  return 0;
16969
17065
  }
16970
17066
  const platform6 = config.platform || detectPlatform();
16971
- log.info(`Reading secrets from: ${envFilePath}`);
16972
17067
  if (config.verbose) {
16973
17068
  log.debug(`Working directory: ${currentDir}`);
16974
17069
  log.debug(`Environment file: ${envFilePath}`);
16975
17070
  log.debug(`Platform: ${platform6}`);
16976
17071
  log.debug(`Dry run mode: ${config.dryRun}`);
16977
17072
  }
16978
- const secrets = parseEnvFile(envFilePath);
17073
+ const secrets = parseSecretsWithFallback(envFilePath, currentDir);
16979
17074
  const secretKeys = Object.keys(secrets);
16980
17075
  if (secretKeys.length === 0) {
16981
17076
  log.info("No secrets found in .env file");
@@ -17036,6 +17131,7 @@ var init_sync_secrets = __esm({
17036
17131
  init_cli_output();
17037
17132
  init_errors();
17038
17133
  init_pathResolver();
17134
+ init_secrets_resolver();
17039
17135
  sync_secrets_default = main5;
17040
17136
  }
17041
17137
  });
@@ -17061,8 +17157,8 @@ async function deploySupabaseFunctions(appDir, config) {
17061
17157
  );
17062
17158
  const functionDirs = readdirSync2(functionsDir).filter((item) => {
17063
17159
  const itemPath = joinPath(functionsDir, item);
17064
- const stat = statSync2(itemPath);
17065
- return stat?.isDirectory() === true;
17160
+ const stat2 = statSync2(itemPath);
17161
+ return stat2?.isDirectory() === true;
17066
17162
  }).filter((dir) => {
17067
17163
  const indexPath = joinPath(functionsDir, dir, "index.ts");
17068
17164
  return pathExists(indexPath);
@@ -18394,9 +18490,11 @@ function processArrayIterations(content, replacements) {
18394
18490
  function isValidFileName(name) {
18395
18491
  return typeof name === "string" && /^[a-zA-Z0-9_-]+$/.test(name);
18396
18492
  }
18397
- var RESERVED_APP_NAME = "demo";
18493
+ var RESERVED_APP_NAMES = ["demo", "dndev"];
18398
18494
  function isReservedAppName(name) {
18399
- return name.toLowerCase() === RESERVED_APP_NAME;
18495
+ return RESERVED_APP_NAMES.includes(
18496
+ name.toLowerCase()
18497
+ );
18400
18498
  }
18401
18499
  async function updateRootPackageJson(rootDir, appNames) {
18402
18500
  const packageJsonPath = joinPath(rootDir, "package.json");
@@ -18696,7 +18794,7 @@ var PROJECT_QUESTIONNAIRE = [
18696
18794
  },
18697
18795
  {
18698
18796
  id: "appNames",
18699
- question: `App name(s) (comma-separated for multiple, e.g., web, admin) - '${RESERVED_APP_NAME}' reserved`,
18797
+ question: `App name(s) (comma-separated for multiple, e.g., web, admin) - '${RESERVED_APP_NAMES.join("', '")}' reserved`,
18700
18798
  type: "input",
18701
18799
  defaultValue: "web"
18702
18800
  }
@@ -18787,48 +18885,168 @@ async function deployFrontend(appDir, serviceAccountPath, projectId, config) {
18787
18885
  init_utils();
18788
18886
  init_cli_output();
18789
18887
  init_vercel_token();
18790
- import { spawnSync as spawnSync6 } from "node:child_process";
18888
+ init_pathResolver();
18889
+ import { createHash } from "node:crypto";
18890
+ import { readFile, readdir as readdir2 } from "node:fs/promises";
18891
+ import { join as join3, relative as relative3 } from "node:path";
18892
+ var VERCEL_API = "https://api.vercel.com";
18893
+ var UPLOAD_BATCH_SIZE = 10;
18894
+ var POLL_INTERVAL_MS = 3e3;
18895
+ var POLL_MAX_ATTEMPTS = 100;
18896
+ function apiHeaders(token, extra) {
18897
+ return { Authorization: `Bearer ${token}`, ...extra };
18898
+ }
18899
+ function teamQuery(orgId) {
18900
+ return `?teamId=${encodeURIComponent(orgId)}`;
18901
+ }
18902
+ async function collectDistFiles(distDir) {
18903
+ const files = [];
18904
+ async function walk(dir) {
18905
+ const entries = await readdir2(dir, { withFileTypes: true });
18906
+ for (const entry of entries) {
18907
+ const fullPath = join3(dir, entry.name);
18908
+ if (entry.isDirectory()) {
18909
+ await walk(fullPath);
18910
+ } else {
18911
+ const content = await readFile(fullPath);
18912
+ const sha = createHash("sha1").update(content).digest("hex");
18913
+ const rel = relative3(distDir, fullPath).split("\\").join("/");
18914
+ files.push({
18915
+ relativePath: rel,
18916
+ content,
18917
+ sha,
18918
+ size: content.byteLength
18919
+ });
18920
+ }
18921
+ }
18922
+ }
18923
+ await walk(distDir);
18924
+ return files;
18925
+ }
18926
+ async function uploadFiles(files, token, orgId) {
18927
+ const q2 = teamQuery(orgId);
18928
+ for (let i = 0; i < files.length; i += UPLOAD_BATCH_SIZE) {
18929
+ const batch = files.slice(i, i + UPLOAD_BATCH_SIZE);
18930
+ await Promise.all(
18931
+ batch.map(async (file) => {
18932
+ const res = await fetch(`${VERCEL_API}/v2/files${q2}`, {
18933
+ method: "POST",
18934
+ headers: apiHeaders(token, {
18935
+ "Content-Type": "application/octet-stream",
18936
+ "x-vercel-digest": file.sha,
18937
+ "Content-Length": String(file.size)
18938
+ }),
18939
+ body: new Uint8Array(file.content)
18940
+ });
18941
+ if (!res.ok) {
18942
+ const body = await res.text();
18943
+ throw new Error(
18944
+ `File upload failed for ${file.relativePath} (${res.status}): ${body}`
18945
+ );
18946
+ }
18947
+ })
18948
+ );
18949
+ }
18950
+ }
18951
+ async function createDeployment(files, token, orgId, projectId) {
18952
+ const q2 = teamQuery(orgId);
18953
+ const body = {
18954
+ project: projectId,
18955
+ target: "production",
18956
+ files: files.map((f) => ({
18957
+ file: f.relativePath,
18958
+ sha: f.sha,
18959
+ size: f.size
18960
+ })),
18961
+ projectSettings: {
18962
+ buildCommand: "",
18963
+ installCommand: "",
18964
+ outputDirectory: "."
18965
+ }
18966
+ };
18967
+ const res = await fetch(`${VERCEL_API}/v13/deployments${q2}`, {
18968
+ method: "POST",
18969
+ headers: apiHeaders(token, { "Content-Type": "application/json" }),
18970
+ body: JSON.stringify(body)
18971
+ });
18972
+ if (!res.ok) {
18973
+ const text = await res.text();
18974
+ throw new Error(`Create deployment failed (${res.status}): ${text}`);
18975
+ }
18976
+ return await res.json();
18977
+ }
18978
+ async function waitForReady(deploymentId, token, orgId) {
18979
+ const q2 = teamQuery(orgId);
18980
+ for (let attempt = 0; attempt < POLL_MAX_ATTEMPTS; attempt++) {
18981
+ const res = await fetch(
18982
+ `${VERCEL_API}/v13/deployments/${deploymentId}${q2}`,
18983
+ { headers: apiHeaders(token) }
18984
+ );
18985
+ if (!res.ok) {
18986
+ const text = await res.text();
18987
+ throw new Error(
18988
+ `Deployment status check failed (${res.status}): ${text}`
18989
+ );
18990
+ }
18991
+ const data = await res.json();
18992
+ if (data.readyState === "READY") return data;
18993
+ if (data.readyState === "ERROR") {
18994
+ throw new Error(
18995
+ `Deployment failed: ${data.errorMessage || "Unknown error"}`
18996
+ );
18997
+ }
18998
+ if (data.readyState === "CANCELED") {
18999
+ throw new Error("Deployment was canceled");
19000
+ }
19001
+ await new Promise((r2) => setTimeout(r2, POLL_INTERVAL_MS));
19002
+ }
19003
+ throw new Error("Deployment timed out (5+ minutes)");
19004
+ }
18791
19005
  async function deployVercelFrontend(appDir, _config) {
18792
19006
  const result = resolveVercelCredentials(appDir);
18793
19007
  if (result.missing) {
19008
+ const secretVars = result.missing.filter((v2) => v2 === "VERCEL_TOKEN");
19009
+ const appVars = result.missing.filter((v2) => v2 !== "VERCEL_TOKEN");
19010
+ const hints = [];
19011
+ if (secretVars.length > 0)
19012
+ hints.push("Add VERCEL_TOKEN to .dndev.secrets at project root.");
19013
+ if (appVars.length > 0)
19014
+ hints.push(`Add ${appVars.join(", ")} to apps/<app>/.env`);
18794
19015
  throw new Error(
18795
- `Missing Vercel credentials in .env.local: ${result.missing.join(", ")}
18796
- Add them to apps/<app>/.env.local \u2014 see guides/dndev/SETUP_VERCEL.md`
19016
+ `Missing Vercel credentials: ${result.missing.join(", ")}
19017
+ ` + hints.join("\n") + "\nSee guides/dndev/SETUP_VERCEL.md"
18797
19018
  );
18798
19019
  }
18799
19020
  const { token, orgId, projectId } = result.credentials;
18800
- log.debug("Using Vercel credentials from .env (token-based auth)");
18801
- log.info("Deploying to Vercel...");
18802
- const deployResult = spawnSync6(
18803
- "bunx",
18804
- ["vercel", "deploy", "--prod", "--yes", "--token", token],
18805
- {
18806
- cwd: appDir,
18807
- // stdout piped to capture deployment URL, stderr inherits for progress
18808
- stdio: ["inherit", "pipe", "inherit"],
18809
- encoding: "utf-8",
18810
- env: {
18811
- ...process.env,
18812
- VERCEL_ORG_ID: orgId,
18813
- VERCEL_PROJECT_ID: projectId
18814
- }
18815
- }
18816
- );
18817
- if (deployResult.status !== 0) {
18818
- throw new Error(`vercel deploy exited with code ${deployResult.status}`);
18819
- }
18820
- const deployUrl = deployResult.stdout?.trim();
18821
- if (deployUrl) {
18822
- log.success(`Production: ${deployUrl}`);
18823
- } else {
18824
- log.success("Frontend deployed to Vercel");
19021
+ const distDir = joinPath(appDir, "dist");
19022
+ if (!pathExists(distDir)) {
19023
+ throw new Error(`dist/ not found at ${distDir}. Run build first.`);
19024
+ }
19025
+ log.debug("Using Vercel REST API (token-based, no CLI)");
19026
+ log.info("Collecting dist/ files...");
19027
+ const files = await collectDistFiles(distDir);
19028
+ if (files.length === 0) {
19029
+ throw new Error("dist/ is empty \u2014 nothing to deploy.");
19030
+ }
19031
+ log.info(`Found ${files.length} files`);
19032
+ log.info("Uploading files to Vercel...");
19033
+ await uploadFiles(files, token, orgId);
19034
+ log.success(`${files.length} files uploaded`);
19035
+ log.info("Creating production deployment...");
19036
+ const deployment = await createDeployment(files, token, orgId, projectId);
19037
+ log.info(`Deployment ${deployment.id} created, waiting...`);
19038
+ const ready = await waitForReady(deployment.id, token, orgId);
19039
+ const prodUrl = `https://${ready.url}`;
19040
+ log.success(`Production: ${prodUrl}`);
19041
+ if (ready.alias?.length) {
19042
+ log.info(`Aliases: ${ready.alias.join(", ")}`);
18825
19043
  }
18826
19044
  }
18827
19045
 
18828
19046
  // packages/tooling/src/apps/deploy-functions.ts
18829
19047
  init_utils();
18830
19048
  var import_yaml = __toESM(require_dist(), 1);
18831
- import { execSync as execSync8, spawnSync as spawnSync7 } from "node:child_process";
19049
+ import { execSync as execSync8, spawnSync as spawnSync6 } from "node:child_process";
18832
19050
  init_pathResolver();
18833
19051
  init_cli_tools();
18834
19052
  init_typed_file_operations();
@@ -19015,7 +19233,7 @@ function updateCloudRunIAM(functionNames, projectId, region, serviceAccountPath,
19015
19233
  let failCount = 0;
19016
19234
  for (const funcName of functionNames) {
19017
19235
  try {
19018
- const result = spawnSync7(
19236
+ const result = spawnSync6(
19019
19237
  "gcloud",
19020
19238
  [
19021
19239
  "run",
@@ -19133,7 +19351,7 @@ async function autoSyncSecrets(functionsDir, projectId, config) {
19133
19351
  let failCount = 0;
19134
19352
  for (const { key, value } of secrets) {
19135
19353
  try {
19136
- const result = spawnSync7(
19354
+ const result = spawnSync6(
19137
19355
  firebaseCmd,
19138
19356
  ["functions:secrets:set", key, "--project", projectId],
19139
19357
  {
@@ -19320,7 +19538,7 @@ async function deployRules(appDir, serviceAccountPath, projectId, config, option
19320
19538
 
19321
19539
  // packages/tooling/src/apps/deploy-utils.ts
19322
19540
  init_utils();
19323
- import { spawnSync as spawnSync8 } from "node:child_process";
19541
+ import { spawnSync as spawnSync7 } from "node:child_process";
19324
19542
  init_pathResolver();
19325
19543
  init_typed_file_operations();
19326
19544
  init_error_handling();
@@ -19332,8 +19550,8 @@ function detectAvailableApps() {
19332
19550
  }
19333
19551
  return readdirSync2(appsDir).filter((item) => {
19334
19552
  const itemPath = joinPath(appsDir, item);
19335
- const stat = statSync2(itemPath);
19336
- return stat?.isDirectory() === true;
19553
+ const stat2 = statSync2(itemPath);
19554
+ return stat2?.isDirectory() === true;
19337
19555
  }).filter((app) => {
19338
19556
  const appDir = joinPath(appsDir, app);
19339
19557
  const firebaseJsonPath = joinPath(appDir, "firebase.json");
@@ -19508,7 +19726,7 @@ How to fix:
19508
19726
  if (shouldOpen) {
19509
19727
  try {
19510
19728
  const openCommand = process.platform === "win32" ? "start" : process.platform === "darwin" ? "open" : "xdg-open";
19511
- spawnSync8(openCommand, [consoleUrl], { shell: true });
19729
+ spawnSync7(openCommand, [consoleUrl], { shell: true });
19512
19730
  log.success("Opening Firebase Console...");
19513
19731
  } catch {
19514
19732
  log.warn("Could not open browser. Please open the URL manually.");
@@ -19939,12 +20157,6 @@ async function main6(options = {}) {
19939
20157
  ...serviceAccountPath ? [`Service Account: ${serviceAccountPath}`] : []
19940
20158
  ].join("\n");
19941
20159
  Me(configNote, "Deployment Configuration");
19942
- if (shouldDeployVercelFrontend) {
19943
- requireCLI(
19944
- CLI_TOOLS.VERCEL,
19945
- "Vercel CLI is required to deploy the frontend.\nInstall: bun install -g vercel"
19946
- );
19947
- }
19948
20160
  if (shouldDeployFirebaseFrontend && serviceAccountPath && config.project) {
19949
20161
  await deployFrontend(appDir, serviceAccountPath, config.project, config);
19950
20162
  }
@@ -20075,6 +20287,11 @@ function generateScripts(templateName, options) {
20075
20287
  scripts.build = "tsc --noEmit && vite build --mode production";
20076
20288
  scripts.preview = "vite preview";
20077
20289
  scripts["type-check"] = "tsc --noEmit";
20290
+ } else if (templateName === "dndev") {
20291
+ scripts.dev = "vite";
20292
+ scripts.build = "tsc --noEmit && vite build --mode production";
20293
+ scripts.preview = "vite preview";
20294
+ scripts["type-check"] = "tsc --noEmit";
20078
20295
  } else if (templateName === "entities") {
20079
20296
  }
20080
20297
  return scripts;
@@ -20202,7 +20419,7 @@ function resolveDeployConfig(host, backend) {
20202
20419
  return "vercel-vercel";
20203
20420
  }
20204
20421
  function getScaffoldParts(builder, host, functions, backend) {
20205
- const baseTemplate = builder === "nextjs" ? "app-next" : builder === "demo" ? "app-demo" : `app-${builder}`;
20422
+ const baseTemplate = builder === "nextjs" ? "app-next" : builder === "demo" ? "app-demo" : builder === "dndev" ? "app-dndev" : `app-${builder}`;
20206
20423
  return {
20207
20424
  builder,
20208
20425
  backend,
@@ -20230,7 +20447,7 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
20230
20447
  Ie("\u{1F680} DoNotDev App Creator");
20231
20448
  if (!appName) {
20232
20449
  appName = await askForInput(
20233
- `App name - '${RESERVED_APP_NAME}' reserved`,
20450
+ `App name - '${RESERVED_APP_NAMES.join("', '")}' reserved`,
20234
20451
  "my-app"
20235
20452
  );
20236
20453
  if (!isValidFileName(appName)) {
@@ -20431,12 +20648,13 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
20431
20648
  }
20432
20649
  }
20433
20650
  const executionMode = detectExecutionMode();
20434
- const templateName = appTemplate === "demo" ? "demo" : executionMode === "development" ? `dev-${appTemplate}` : `consumer-${appTemplate}`;
20651
+ const isReservedTemplate = appTemplate === "demo" || appTemplate === "dndev";
20652
+ const templateName = isReservedTemplate ? appTemplate : executionMode === "development" ? `dev-${appTemplate}` : `consumer-${appTemplate}`;
20435
20653
  const packageJson = generatePackageJson(templateName, executionMode, {
20436
20654
  appName,
20437
- template: appTemplate === "demo" ? "vite" : appTemplate,
20655
+ template: isReservedTemplate ? "vite" : appTemplate,
20438
20656
  includeFunctions: Boolean(row.functionsTemplate),
20439
- platform: appTemplate === "demo" ? void 0 : backendPlatform
20657
+ platform: isReservedTemplate ? void 0 : backendPlatform
20440
20658
  });
20441
20659
  const packageJsonPath = joinPath(appDir, "package.json");
20442
20660
  await write(packageJsonPath, packageJson, {
@@ -20868,6 +21086,10 @@ async function main9(options) {
20868
21086
  "Would you like to install the demo app? (component showcase)",
20869
21087
  false
20870
21088
  );
21089
+ let installCockpitApp = await askForConfirmation(
21090
+ "Would you like to install the cockpit app? (AI development dashboard)",
21091
+ false
21092
+ );
20871
21093
  let allAppNames = [...appNames];
20872
21094
  let appsToCreate = [];
20873
21095
  let appsToSkip = [];
@@ -20991,6 +21213,13 @@ async function main9(options) {
20991
21213
  const primaryPlatform = Object.values(appConfigs).find(
20992
21214
  (c) => c.backend !== "none"
20993
21215
  )?.backend ?? "firebase";
21216
+ const hasVercel = Object.values(appConfigs).some(
21217
+ (c) => c.host === "vercel"
21218
+ );
21219
+ const hasSupabase = Object.values(appConfigs).some(
21220
+ (c) => c.backend === "supabase"
21221
+ );
21222
+ const hasBilling = Object.values(appConfigs).some((c) => c.billing);
20994
21223
  const rootPackageJson = generatePackageJson(
20995
21224
  "consumer-root",
20996
21225
  executionMode,
@@ -21025,8 +21254,12 @@ async function main9(options) {
21025
21254
  // Determined by agent in WAI-WAY Phase 0
21026
21255
  needsOAuth: false,
21027
21256
  // Determined by agent in WAI-WAY Phase 0
21028
- needsBilling: false
21257
+ needsBilling: false,
21029
21258
  // Determined by agent in WAI-WAY Phase 0
21259
+ // .dndev.secrets conditional sections
21260
+ vercel: hasVercel,
21261
+ supabase: hasSupabase,
21262
+ stripe: hasBilling
21030
21263
  };
21031
21264
  const firebaseRootFiles = /* @__PURE__ */ new Set([
21032
21265
  "firebase.json.example",
@@ -21055,6 +21288,13 @@ async function main9(options) {
21055
21288
  await replacePlaceholders(destPath, rootReplacements);
21056
21289
  }
21057
21290
  }
21291
+ const dndevSecretsPath = joinPath(projectDirNormalized, ".dndev.secrets");
21292
+ if (pathExists(dndevSecretsPath)) {
21293
+ await copy(
21294
+ dndevSecretsPath,
21295
+ joinPath(projectDirNormalized, ".dndev.secrets.example")
21296
+ );
21297
+ }
21058
21298
  if (setupGithubActions) {
21059
21299
  const ciTemplateDir = joinPath(templatesRoot, "github");
21060
21300
  await copyTemplateFiles(
@@ -21155,6 +21395,61 @@ async function main9(options) {
21155
21395
  sDemo.stop("Demo app copied");
21156
21396
  }
21157
21397
  }
21398
+ if (installCockpitApp) {
21399
+ const sCockpit = Y2();
21400
+ sCockpit.start("Copying cockpit app...");
21401
+ const cockpitAppDir = joinPath(projectDirNormalized, "apps", "dndev");
21402
+ const cockpitTemplateDir = joinPath(templatesRoot, "app-dndev");
21403
+ if (pathExists(cockpitAppDir)) {
21404
+ if (isMergeMode) {
21405
+ const cockpitAction = await askForSelection(
21406
+ "Cockpit app already exists. What would you like to do?",
21407
+ [
21408
+ { title: "Replace (delete and recreate)", value: "replace" },
21409
+ { title: "Skip (keep existing)", value: "skip" }
21410
+ ],
21411
+ 1
21412
+ );
21413
+ if (cockpitAction === "replace") {
21414
+ await remove(cockpitAppDir);
21415
+ } else {
21416
+ sCockpit.stop("Cockpit app skipped (already exists)");
21417
+ installCockpitApp = false;
21418
+ }
21419
+ } else {
21420
+ await remove(cockpitAppDir);
21421
+ }
21422
+ }
21423
+ if (installCockpitApp) {
21424
+ const cockpitFirebaseProjectId = projectName.toLowerCase().replace(/\s+/g, "-");
21425
+ await copyTemplateFiles(cockpitTemplateDir, cockpitAppDir, {
21426
+ projectName,
21427
+ appName: "dndev",
21428
+ includeFunctions: false,
21429
+ needsCRUD: false,
21430
+ setupGithubActions: false,
21431
+ appNames,
21432
+ firebaseProjectId: cockpitFirebaseProjectId,
21433
+ firebaseRegion: "europe-west1",
21434
+ firebaseSecretName: projectName.toUpperCase().replace(/-/g, "_"),
21435
+ YOUR_FIREBASE_PROJECT_ID: cockpitFirebaseProjectId,
21436
+ YOUR_REGION: "europe-west1",
21437
+ monorepoRelativePath: executionMode === "development" ? calculateRelativePath(projectDirNormalized, monorepoRoot) : "",
21438
+ appTemplate: "dndev"
21439
+ });
21440
+ const packageJson = generatePackageJson("dndev", executionMode, {
21441
+ appName: "dndev",
21442
+ template: "vite",
21443
+ includeFunctions: false
21444
+ });
21445
+ const packageJsonPath = joinPath(cockpitAppDir, "package.json");
21446
+ await write(packageJsonPath, packageJson, {
21447
+ format: "json",
21448
+ overwrite: true
21449
+ });
21450
+ sCockpit.stop("Cockpit app copied");
21451
+ }
21452
+ }
21158
21453
  log.info("Creating apps...");
21159
21454
  for (const appName of appNames) {
21160
21455
  const appConfig = appConfigs[appName];
@@ -21200,7 +21495,7 @@ init_utils();
21200
21495
  init_cli_output();
21201
21496
  init_errors();
21202
21497
  init_pathResolver();
21203
- import { spawnSync as spawnSync10 } from "node:child_process";
21498
+ import { spawnSync as spawnSync9 } from "node:child_process";
21204
21499
  import { EOL as EOL2 } from "node:os";
21205
21500
  async function main10(options = {}) {
21206
21501
  const dryRun = options.dryRun ?? false;
@@ -21680,7 +21975,7 @@ async function runPrettier(rootDir, dryRun, verbose) {
21680
21975
  log.info("DRY RUN: Would run Prettier");
21681
21976
  return stats;
21682
21977
  }
21683
- const result = spawnSync10("bunx", prettierArgs, {
21978
+ const result = spawnSync9("bunx", prettierArgs, {
21684
21979
  cwd: rootDir,
21685
21980
  stdio: "pipe",
21686
21981
  shell: true,
@@ -21851,8 +22146,8 @@ async function findCacheItems(targetDir, verbose) {
21851
22146
  for (const nestedPkg of nestedPackages) {
21852
22147
  const nestedPkgPath = joinPath(pkgPath, nestedPkg);
21853
22148
  try {
21854
- const stat = statSync2(nestedPkgPath);
21855
- if (stat?.isDirectory()) {
22149
+ const stat2 = statSync2(nestedPkgPath);
22150
+ if (stat2?.isDirectory()) {
21856
22151
  check(joinPath(nestedPkgPath, ".vite"));
21857
22152
  check(joinPath(nestedPkgPath, "dist"));
21858
22153
  check(joinPath(nestedPkgPath, "node_modules", ".vite"));