@donotdev/cli 0.0.17 → 0.0.18

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 (61) hide show
  1. package/dependencies-matrix.json +166 -58
  2. package/dist/bin/commands/create-app.js +89 -140
  3. package/dist/bin/commands/create-project.js +90 -144
  4. package/dist/bin/dndev.js +9 -6
  5. package/dist/bin/donotdev.js +9 -6
  6. package/dist/index.js +97 -148
  7. package/package.json +1 -1
  8. package/templates/root-consumer/.claude/commands/brainstorm.md.example +15 -1
  9. package/templates/root-consumer/.claude/commands/build.md.example +24 -2
  10. package/templates/root-consumer/.claude/commands/design.md.example +17 -0
  11. package/templates/root-consumer/.claude/commands/polish.md.example +17 -0
  12. package/templates/root-consumer/AI.md.example +50 -18
  13. package/templates/root-consumer/guides/dndev/SETUP_PAGES.md.example +64 -0
  14. package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +1 -1
  15. package/templates/functions-firebase/functions-firebase/README.md.example +0 -123
  16. package/templates/functions-firebase/functions-firebase/build.mjs.example +0 -5
  17. package/templates/functions-firebase/functions-firebase/src/auth/getCustomClaims.ts.example +0 -19
  18. package/templates/functions-firebase/functions-firebase/src/auth/getUserAuthStatus.ts.example +0 -21
  19. package/templates/functions-firebase/functions-firebase/src/auth/index.ts.example +0 -11
  20. package/templates/functions-firebase/functions-firebase/src/auth/removeCustomClaims.ts.example +0 -21
  21. package/templates/functions-firebase/functions-firebase/src/auth/setCustomClaims.ts.example +0 -21
  22. package/templates/functions-firebase/functions-firebase/src/billing/handleStripeWebhook.ts.example +0 -24
  23. package/templates/functions-firebase/functions-firebase/src/billing/index.ts.example +0 -10
  24. package/templates/functions-firebase/functions-firebase/src/billing/processPaymentSuccess.ts.example +0 -14
  25. package/templates/functions-firebase/functions-firebase/src/billing/refreshSubscriptionStatus.ts.example +0 -14
  26. package/templates/functions-firebase/functions-firebase/src/index.ts.example +0 -39
  27. package/templates/functions-firebase/functions-firebase/src/oauth/checkGitHubAccess.ts.example +0 -14
  28. package/templates/functions-firebase/functions-firebase/src/oauth/disconnect.ts.example +0 -14
  29. package/templates/functions-firebase/functions-firebase/src/oauth/exchangeToken.ts.example +0 -14
  30. package/templates/functions-firebase/functions-firebase/src/oauth/getConnections.ts.example +0 -14
  31. package/templates/functions-firebase/functions-firebase/src/oauth/grantGitHubAccess.ts.example +0 -14
  32. package/templates/functions-firebase/functions-firebase/src/oauth/index.ts.example +0 -17
  33. package/templates/functions-firebase/functions-firebase/src/oauth/refreshToken.ts.example +0 -14
  34. package/templates/functions-firebase/functions-firebase/src/oauth/revokeGitHubAccess.ts.example +0 -14
  35. package/templates/functions-firebase/functions-firebase/tsconfig.json.example +0 -21
  36. package/templates/functions-vercel/functions-vercel/README.md.example +0 -116
  37. package/templates/functions-vercel/functions-vercel/build.mjs.example +0 -52
  38. package/templates/functions-vercel/functions-vercel/src/api/auth/getCustomClaims.ts.example +0 -20
  39. package/templates/functions-vercel/functions-vercel/src/api/auth/getUserAuthStatus.ts.example +0 -20
  40. package/templates/functions-vercel/functions-vercel/src/api/auth/removeCustomClaims.ts.example +0 -20
  41. package/templates/functions-vercel/functions-vercel/src/api/auth/setCustomClaims.ts.example +0 -20
  42. package/templates/functions-vercel/functions-vercel/src/api/billing/handleStripeWebhook.ts.example +0 -20
  43. package/templates/functions-vercel/functions-vercel/src/api/billing/processPaymentSuccess.ts.example +0 -20
  44. package/templates/functions-vercel/functions-vercel/src/api/billing/refreshSubscriptionStatus.ts.example +0 -20
  45. package/templates/functions-vercel/functions-vercel/src/api/crud/createEntity.ts.example +0 -20
  46. package/templates/functions-vercel/functions-vercel/src/api/crud/deleteEntity.ts.example +0 -20
  47. package/templates/functions-vercel/functions-vercel/src/api/crud/getEntity.ts.example +0 -20
  48. package/templates/functions-vercel/functions-vercel/src/api/crud/listEntities.ts.example +0 -20
  49. package/templates/functions-vercel/functions-vercel/src/api/crud/updateEntity.ts.example +0 -20
  50. package/templates/functions-vercel/functions-vercel/src/api/oauth/checkGitHubAccess.ts.example +0 -20
  51. package/templates/functions-vercel/functions-vercel/src/api/oauth/disconnect.ts.example +0 -20
  52. package/templates/functions-vercel/functions-vercel/src/api/oauth/exchangeToken.ts.example +0 -20
  53. package/templates/functions-vercel/functions-vercel/src/api/oauth/getConnections.ts.example +0 -20
  54. package/templates/functions-vercel/functions-vercel/src/api/oauth/grantGitHubAccess.ts.example +0 -20
  55. package/templates/functions-vercel/functions-vercel/src/api/oauth/refreshToken.ts.example +0 -20
  56. package/templates/functions-vercel/functions-vercel/src/api/oauth/revokeGitHubAccess.ts.example +0 -20
  57. package/templates/functions-vercel/functions-vercel/tsconfig.json.example +0 -21
  58. package/templates/functions-vercel/functions-vercel/vercel.json.example +0 -14
  59. package/templates/github/github/workflows/firebase-deploy.yml.example +0 -79
  60. /package/templates/functions-firebase/{functions-firebase/.env.example.example → .env.example} +0 -0
  61. /package/templates/functions-vercel/{functions-vercel/.env.example.example → .env.example} +0 -0
package/dist/bin/dndev.js CHANGED
@@ -49,7 +49,7 @@ Usage: dndev <command>[:<app>] [options]
49
49
 
50
50
  Commands:
51
51
  init, create-project Create a new DoNotDev project
52
- create-app [name] Add app (--builder vite|next, --functions, --project <id>)
52
+ create-app [name] Add app (--builder, --host, --functions, --backend)
53
53
  dev [app] Start development server
54
54
  build [app] Build for production
55
55
  preview [app] Preview production build
@@ -74,9 +74,10 @@ Options:
74
74
  Examples:
75
75
  dndev init my-project Create a new project
76
76
  dndev create-app Interactive app creation
77
- dndev create-app my-app Create 'my-app' with defaults (vite, no functions)
78
- dndev create-app my-app --builder next --functions Next.js + functions
79
- dndev create-app my-app --functions --project my-fb-id Set Firebase project (2-min setup)
77
+ dndev create-app my-app Create 'my-app' with defaults (vite, frontend-only)
78
+ dndev create-app my-app --builder next --host vercel Next.js + Vercel hosting
79
+ dndev create-app my-app --functions firebase --backend firebase Full Firebase stack
80
+ dndev create-app my-app --backend supabase --project my-fb-id Supabase + custom project
80
81
  dndev dev Start dev server
81
82
  dndev dev:web Start dev server for 'web' app
82
83
  dndev agent Configure MCP for all AI agents
@@ -101,14 +102,16 @@ program.command("init [name]").alias("create-project").description("Create a new
101
102
  const { main } = await import("./commands/create-project.js");
102
103
  await main({ projectName: name });
103
104
  });
104
- program.command("create-app [name]").description("Add a new app to existing project").option("--name <name>", "App name (non-interactive)").option("--builder <builder>", "Framework: vite or next (default: vite)").option("--functions", "Include Firebase functions").option("--project <id>", "Firebase project ID (default: app name)").option("--region <region>", "Firebase region (default: europe-west1)").action(async (name, options) => {
105
+ program.command("create-app [name]").description("Add a new app to existing project").option("--name <name>", "App name (non-interactive)").option("--builder <builder>", "Framework: vite, next, or expo (default: vite)").option("--host <host>", "Hosting: none, vercel, or firebase (default: none)").option("--functions <runtime>", "Functions: none, vercel, firebase, or supabase (default: none)").option("--backend <backend>", "BaaS: none, firebase, or supabase (default: none)").option("--project <id>", "Firebase project ID (default: app name)").option("--region <region>", "Firebase region (default: europe-west1)").action(async (name, options) => {
105
106
  const { main } = await import("./commands/create-app.js");
106
107
  const appName = name || options.name;
107
108
  if (appName) {
108
109
  await main({
109
110
  name: appName,
110
111
  builder: options.builder,
112
+ host: options.host,
111
113
  functions: options.functions,
114
+ backend: options.backend,
112
115
  firebaseProjectId: options.project,
113
116
  firebaseRegion: options.region
114
117
  });
@@ -252,7 +255,7 @@ program.command("wai").alias("wai-way").description("Output WAI-WAY activation p
252
255
  function preprocessArgs(args2) {
253
256
  if (args2.length === 0) return args2;
254
257
  const firstArg = args2[0];
255
- const appCommands = ["dev", "build", "preview", "emu", "deploy", "staging"];
258
+ const appCommands = ["dev", "build", "preview", "emu", "deploy", "staging", "tc", "type-check", "cacheout", "co"];
256
259
  if (firstArg && firstArg.includes(":")) {
257
260
  const colonIndex = firstArg.indexOf(":");
258
261
  const command = firstArg.substring(0, colonIndex);
@@ -49,7 +49,7 @@ Usage: dndev <command>[:<app>] [options]
49
49
 
50
50
  Commands:
51
51
  init, create-project Create a new DoNotDev project
52
- create-app [name] Add app (--builder vite|next, --functions, --project <id>)
52
+ create-app [name] Add app (--builder, --host, --functions, --backend)
53
53
  dev [app] Start development server
54
54
  build [app] Build for production
55
55
  preview [app] Preview production build
@@ -74,9 +74,10 @@ Options:
74
74
  Examples:
75
75
  dndev init my-project Create a new project
76
76
  dndev create-app Interactive app creation
77
- dndev create-app my-app Create 'my-app' with defaults (vite, no functions)
78
- dndev create-app my-app --builder next --functions Next.js + functions
79
- dndev create-app my-app --functions --project my-fb-id Set Firebase project (2-min setup)
77
+ dndev create-app my-app Create 'my-app' with defaults (vite, frontend-only)
78
+ dndev create-app my-app --builder next --host vercel Next.js + Vercel hosting
79
+ dndev create-app my-app --functions firebase --backend firebase Full Firebase stack
80
+ dndev create-app my-app --backend supabase --project my-fb-id Supabase + custom project
80
81
  dndev dev Start dev server
81
82
  dndev dev:web Start dev server for 'web' app
82
83
  dndev agent Configure MCP for all AI agents
@@ -101,14 +102,16 @@ program.command("init [name]").alias("create-project").description("Create a new
101
102
  const { main } = await import("./commands/create-project.js");
102
103
  await main({ projectName: name });
103
104
  });
104
- program.command("create-app [name]").description("Add a new app to existing project").option("--name <name>", "App name (non-interactive)").option("--builder <builder>", "Framework: vite or next (default: vite)").option("--functions", "Include Firebase functions").option("--project <id>", "Firebase project ID (default: app name)").option("--region <region>", "Firebase region (default: europe-west1)").action(async (name, options) => {
105
+ program.command("create-app [name]").description("Add a new app to existing project").option("--name <name>", "App name (non-interactive)").option("--builder <builder>", "Framework: vite, next, or expo (default: vite)").option("--host <host>", "Hosting: none, vercel, or firebase (default: none)").option("--functions <runtime>", "Functions: none, vercel, firebase, or supabase (default: none)").option("--backend <backend>", "BaaS: none, firebase, or supabase (default: none)").option("--project <id>", "Firebase project ID (default: app name)").option("--region <region>", "Firebase region (default: europe-west1)").action(async (name, options) => {
105
106
  const { main } = await import("./commands/create-app.js");
106
107
  const appName = name || options.name;
107
108
  if (appName) {
108
109
  await main({
109
110
  name: appName,
110
111
  builder: options.builder,
112
+ host: options.host,
111
113
  functions: options.functions,
114
+ backend: options.backend,
112
115
  firebaseProjectId: options.project,
113
116
  firebaseRegion: options.region
114
117
  });
@@ -252,7 +255,7 @@ program.command("wai").alias("wai-way").description("Output WAI-WAY activation p
252
255
  function preprocessArgs(args2) {
253
256
  if (args2.length === 0) return args2;
254
257
  const firstArg = args2[0];
255
- const appCommands = ["dev", "build", "preview", "emu", "deploy", "staging"];
258
+ const appCommands = ["dev", "build", "preview", "emu", "deploy", "staging", "tc", "type-check", "cacheout", "co"];
256
259
  if (firstArg && firstArg.includes(":")) {
257
260
  const colonIndex = firstArg.indexOf(":");
258
261
  const command = firstArg.substring(0, colonIndex);
package/dist/index.js CHANGED
@@ -18617,34 +18617,67 @@ var APP_QUESTIONNAIRE = [
18617
18617
  ]
18618
18618
  },
18619
18619
  {
18620
- id: "needsBackend",
18621
- question: "Include backend functions?",
18622
- type: "confirm",
18623
- defaultValue: false
18620
+ id: "host",
18621
+ question: "Where will you host?",
18622
+ type: "select",
18623
+ condition: (answers) => answers.framework !== "expo",
18624
+ defaultValue: (answers) => {
18625
+ return answers.framework === "nextjs" ? "vercel" : "none";
18626
+ },
18627
+ choices: [
18628
+ { title: "None \u2014 no hosting config", value: "none" },
18629
+ { title: "Vercel \u2014 edge CDN + serverless", value: "vercel" },
18630
+ { title: "Firebase Hosting \u2014 Google CDN", value: "firebase" }
18631
+ ]
18632
+ },
18633
+ {
18634
+ id: "functions",
18635
+ question: "Serverless functions?",
18636
+ type: "select",
18637
+ defaultValue: "none",
18638
+ // Choices filtered dynamically based on host
18639
+ choices: [
18640
+ { title: "None", value: "none" },
18641
+ { title: "Vercel Functions \u2014 edge + node.js", value: "vercel" },
18642
+ { title: "Firebase Functions \u2014 Google Cloud", value: "firebase" },
18643
+ { title: "Supabase Edge Functions \u2014 Deno", value: "supabase" }
18644
+ ],
18645
+ choicesFilter: (answers) => {
18646
+ const host = answers.host ?? "none";
18647
+ const framework = answers.framework;
18648
+ if (framework === "expo") return ["none", "firebase", "supabase"];
18649
+ if (host === "firebase") return ["none", "firebase"];
18650
+ if (host === "vercel") return ["none", "vercel", "supabase"];
18651
+ return ["none", "vercel", "firebase", "supabase"];
18652
+ }
18624
18653
  },
18625
18654
  {
18626
- id: "backendPlatform",
18627
- question: "Which backend platform?",
18655
+ id: "backend",
18656
+ question: "Backend / BaaS provider?",
18628
18657
  type: "select",
18629
- dependsOn: "needsBackend",
18630
- condition: (answers) => answers.needsBackend === true,
18631
18658
  defaultValue: (answers) => {
18632
- return answers.framework === "nextjs" ? "vercel" : "firebase";
18659
+ if (answers.functions === "firebase") return "firebase";
18660
+ if (answers.functions === "supabase") return "supabase";
18661
+ return "none";
18633
18662
  },
18634
18663
  choices: [
18664
+ { title: "None \u2014 frontend only", value: "none" },
18635
18665
  {
18636
- title: "Firebase \u2014 Full-stack platform (hosting + functions + auth + firestore)",
18666
+ title: "Firebase \u2014 Auth + Firestore + Storage",
18637
18667
  value: "firebase"
18638
18668
  },
18639
- {
18640
- title: "Vercel \u2014 Serverless functions (edge + node.js)",
18641
- value: "vercel"
18642
- },
18643
18669
  {
18644
18670
  title: "Supabase \u2014 Postgres + Auth + Storage",
18645
18671
  value: "supabase"
18646
18672
  }
18647
- ]
18673
+ ],
18674
+ choicesFilter: (answers) => {
18675
+ const functions = answers.functions ?? "none";
18676
+ if (functions === "firebase") return ["none", "firebase"];
18677
+ if (functions === "supabase") return ["none", "supabase"];
18678
+ if (functions === "vercel") return ["none"];
18679
+ return ["none", "firebase", "supabase"];
18680
+ }
18648
18681
  }
18649
18682
  ];
18650
18683
  var PROJECT_QUESTIONNAIRE = [
@@ -18662,12 +18695,13 @@ var PROJECT_QUESTIONNAIRE = [
18662
18695
  }
18663
18696
  ];
18664
18697
  function aggregateRequirements(answers) {
18698
+ const hasBackend = answers.backend && answers.backend !== "none" || answers.functions && answers.functions !== "none";
18665
18699
  const requirements = {
18666
18700
  entities: [],
18667
18701
  // Entities created in apps/<app>/entities/ (v1), root entities/ for v2
18668
18702
  billing: true,
18669
18703
  // Always on (useStripeBillingSafe handles missing package)
18670
- backend: answers.needsBackend || false,
18704
+ backend: hasBackend,
18671
18705
  features: [],
18672
18706
  template: "vite",
18673
18707
  // Only Vite for now
@@ -18691,6 +18725,10 @@ async function runQuestionnaire(questions, initialAnswers, showWIP, askFor) {
18691
18725
  if (!showWIP) {
18692
18726
  choices = choices.filter((choice) => !choice.wip);
18693
18727
  }
18728
+ if (question.choicesFilter) {
18729
+ const allowed = question.choicesFilter(answers);
18730
+ choices = choices.filter((c) => allowed.includes(c.value));
18731
+ }
18694
18732
  if (choices.length === 0) continue;
18695
18733
  answer = await askFor.selection(question.question, choices);
18696
18734
  break;
@@ -20114,120 +20152,22 @@ init_pathResolver();
20114
20152
 
20115
20153
  // packages/tooling/src/scaffolding/scaffold-matrix.ts
20116
20154
  init_utils();
20117
- var MATRIX = [
20118
- {
20119
- builder: "vite",
20120
- backend: "none",
20121
- baseTemplate: "app-vite",
20122
- overlay: null,
20123
- deployConfig: null,
20124
- functionsTemplate: null
20125
- },
20126
- {
20127
- builder: "vite",
20128
- backend: "firebase",
20129
- baseTemplate: "app-vite",
20130
- overlay: "overlay-firebase",
20131
- deployConfig: "firebase",
20132
- functionsTemplate: "functions-firebase"
20133
- },
20134
- {
20135
- builder: "vite",
20136
- backend: "supabase",
20137
- baseTemplate: "app-vite",
20138
- overlay: "overlay-supabase",
20139
- deployConfig: "vercel-supabase",
20140
- functionsTemplate: "functions-supabase"
20141
- },
20142
- {
20143
- builder: "vite",
20144
- backend: "vercel",
20145
- baseTemplate: "app-vite",
20146
- overlay: "overlay-vercel",
20147
- deployConfig: "vercel-vercel",
20148
- functionsTemplate: "functions-vercel"
20149
- },
20150
- {
20151
- builder: "nextjs",
20152
- backend: "none",
20153
- baseTemplate: "app-next",
20154
- overlay: null,
20155
- deployConfig: null,
20156
- functionsTemplate: null
20157
- },
20158
- {
20159
- builder: "nextjs",
20160
- backend: "firebase",
20161
- baseTemplate: "app-next",
20162
- overlay: "overlay-firebase",
20163
- deployConfig: "firebase",
20164
- functionsTemplate: "functions-firebase"
20165
- },
20166
- {
20167
- builder: "nextjs",
20168
- backend: "supabase",
20169
- baseTemplate: "app-next",
20170
- overlay: "overlay-supabase",
20171
- deployConfig: "vercel-supabase",
20172
- functionsTemplate: "functions-supabase"
20173
- },
20174
- {
20175
- builder: "nextjs",
20176
- backend: "vercel",
20177
- baseTemplate: "app-next",
20178
- overlay: "overlay-vercel",
20179
- deployConfig: "vercel-vercel",
20180
- functionsTemplate: "functions-vercel"
20181
- },
20182
- {
20183
- builder: "expo",
20184
- backend: "none",
20185
- baseTemplate: "app-expo",
20186
- overlay: null,
20187
- deployConfig: null,
20188
- functionsTemplate: null
20189
- },
20190
- {
20191
- builder: "expo",
20192
- backend: "firebase",
20193
- baseTemplate: "app-expo",
20194
- overlay: "overlay-firebase",
20195
- deployConfig: null,
20196
- functionsTemplate: "functions-firebase"
20197
- },
20198
- {
20199
- builder: "expo",
20200
- backend: "supabase",
20201
- baseTemplate: "app-expo",
20202
- overlay: "overlay-supabase",
20203
- deployConfig: null,
20204
- functionsTemplate: "functions-supabase"
20205
- },
20206
- {
20207
- builder: "demo",
20208
- backend: "none",
20209
- baseTemplate: "app-demo",
20210
- overlay: null,
20211
- deployConfig: null,
20212
- functionsTemplate: null
20213
- }
20214
- ];
20215
- function comboKey(builder, backend) {
20216
- return `${builder}-${backend}`;
20217
- }
20218
- var ROWS_BY_KEY = /* @__PURE__ */ new Map();
20219
- for (const row of MATRIX) {
20220
- ROWS_BY_KEY.set(comboKey(row.builder, row.backend), row);
20155
+ function resolveDeployConfig(host, backend) {
20156
+ if (host === "none") return null;
20157
+ if (host === "firebase") return "firebase";
20158
+ if (backend === "supabase") return "vercel-supabase";
20159
+ return "vercel-vercel";
20221
20160
  }
20222
- function getScaffoldRow(builder, backend) {
20223
- const key = comboKey(builder, backend);
20224
- const row = ROWS_BY_KEY.get(key);
20225
- if (!row) {
20226
- throw new Error(
20227
- `Unsupported scaffold combo: ${key}. Supported: ${[...ROWS_BY_KEY.keys()].join(", ")}`
20228
- );
20229
- }
20230
- return row;
20161
+ function getScaffoldParts(builder, host, functions, backend) {
20162
+ const baseTemplate = builder === "nextjs" ? "app-next" : builder === "demo" ? "app-demo" : `app-${builder}`;
20163
+ return {
20164
+ builder,
20165
+ backend,
20166
+ baseTemplate,
20167
+ overlay: backend !== "none" ? `overlay-${backend}` : null,
20168
+ deployConfig: resolveDeployConfig(host, backend),
20169
+ functionsTemplate: functions !== "none" ? `functions-${functions}` : null
20170
+ };
20231
20171
  }
20232
20172
 
20233
20173
  // packages/tooling/src/scaffolding/create-app.ts
@@ -20267,11 +20207,15 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
20267
20207
  input: askForInput
20268
20208
  });
20269
20209
  const requirements = aggregateRequirements(answers);
20270
- const defaultPlatform = answers.framework === "nextjs" ? "vercel" : "firebase";
20210
+ const framework = answers.framework || "vite";
20211
+ const host2 = answers.host || "none";
20212
+ const functions2 = answers.functions || "none";
20213
+ const backend2 = answers.backend || "none";
20271
20214
  appConfig = {
20272
- template: answers.framework || "vite",
20273
- needsBackend: answers.needsBackend || false,
20274
- backendPlatform: answers.needsBackend ? answers.backendPlatform || defaultPlatform : void 0,
20215
+ template: framework,
20216
+ host: host2,
20217
+ functions: functions2,
20218
+ backend: backend2,
20275
20219
  needsCRUD: true,
20276
20220
  // Always on
20277
20221
  selectedEntities: [],
@@ -20317,12 +20261,14 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
20317
20261
  s.start(`Creating app: ${appName}`);
20318
20262
  await ensureDir(appDir);
20319
20263
  const builder = appTemplate;
20320
- const backend = appConfig.needsBackend && appConfig.backendPlatform ? appConfig.backendPlatform : "none";
20321
- const row = getScaffoldRow(builder, backend);
20264
+ const host = appConfig.host ?? "none";
20265
+ const functions = appConfig.functions ?? "none";
20266
+ const backend = appConfig.backend ?? "none";
20267
+ const row = getScaffoldParts(builder, host, functions, backend);
20322
20268
  const templateDir = row.baseTemplate;
20323
20269
  const firebaseProjectId = (appConfig?.firebaseProjectId ?? "").trim() || appName.toLowerCase().replace(/\s+/g, "-");
20324
20270
  const firebaseRegion = appConfig?.firebaseRegion ?? "europe-west1";
20325
- const backendPlatform = appConfig.backendPlatform ?? "firebase";
20271
+ const backendPlatform = backend !== "none" ? backend : "firebase";
20326
20272
  const deployConfig = row.deployConfig;
20327
20273
  const replacements = {
20328
20274
  projectName: appName,
@@ -20660,11 +20606,13 @@ Happy coding!`,
20660
20606
  }
20661
20607
  async function main8(options) {
20662
20608
  try {
20663
- const hasExplicitFlags = options?.builder !== void 0 || options?.functions !== void 0;
20609
+ const hasExplicitFlags = options?.builder !== void 0 || options?.host !== void 0 || options?.functions !== void 0 || options?.backend !== void 0;
20664
20610
  if (hasExplicitFlags && options?.name) {
20665
20611
  const appName = options.name;
20666
20612
  const builder = options.builder || "vite";
20667
- const includeFunctions = options.functions ?? false;
20613
+ const hostOpt = options.host ?? "none";
20614
+ const functionsOpt = options.functions ?? "none";
20615
+ const backendOpt = options.backend ?? "none";
20668
20616
  if (!isValidFileName(appName)) {
20669
20617
  throw new Error(
20670
20618
  `Invalid app name "${appName}". Use only letters, numbers, dashes (-), and underscores (_).`
@@ -20677,8 +20625,9 @@ async function main8(options) {
20677
20625
  }
20678
20626
  const appConfig = {
20679
20627
  template: builder === "next" ? "nextjs" : builder === "expo" ? "expo" : "vite",
20680
- needsBackend: includeFunctions,
20681
- backendPlatform: includeFunctions ? "firebase" : void 0,
20628
+ host: hostOpt,
20629
+ functions: functionsOpt,
20630
+ backend: backendOpt,
20682
20631
  needsCRUD: true,
20683
20632
  selectedEntities: [],
20684
20633
  userAuth: "social",
@@ -20710,12 +20659,11 @@ async function collectAppConfig(appName) {
20710
20659
  input: askForInput
20711
20660
  });
20712
20661
  const framework = answers.framework || "vite";
20713
- const needsBackend = answers.needsBackend || false;
20714
- const defaultPlatform = framework === "nextjs" ? "vercel" : "firebase";
20715
20662
  return {
20716
20663
  template: framework,
20717
- needsBackend,
20718
- backendPlatform: needsBackend ? answers.backendPlatform || defaultPlatform : void 0,
20664
+ host: answers.host || "none",
20665
+ functions: answers.functions || "none",
20666
+ backend: answers.backend || "none",
20719
20667
  needsCRUD: false,
20720
20668
  selectedEntities: [],
20721
20669
  userAuth: "none",
@@ -20862,7 +20810,7 @@ async function main9(options) {
20862
20810
  Me(`Configuring "${trimmedName}"...`, "\u2699\uFE0F");
20863
20811
  const config = await collectAppConfig(trimmedName);
20864
20812
  appConfigs[trimmedName] = config;
20865
- if (config.needsBackend) anyAppNeedsBackend = true;
20813
+ if (config.backend !== "none" || config.functions !== "none") anyAppNeedsBackend = true;
20866
20814
  }
20867
20815
  let installDemoApp = await askForConfirmation(
20868
20816
  "Would you like to install the demo app? (component showcase)",
@@ -20938,8 +20886,9 @@ async function main9(options) {
20938
20886
  log.warn(`Missing config for app "${appName}", using defaults`);
20939
20887
  appConfigs[appName] = {
20940
20888
  template: "vite",
20941
- needsBackend: false,
20942
- backendPlatform: void 0,
20889
+ host: "none",
20890
+ functions: "none",
20891
+ backend: "none",
20943
20892
  needsCRUD: false,
20944
20893
  selectedEntities: [],
20945
20894
  userAuth: "none",
@@ -20987,7 +20936,7 @@ async function main9(options) {
20987
20936
  overwrite: true
20988
20937
  });
20989
20938
  const relativeMonorepoPath = executionMode === "development" ? calculateRelativePath(projectDirNormalized, monorepoRoot) : "";
20990
- const primaryPlatform = Object.values(appConfigs).find((c) => c.backendPlatform)?.backendPlatform ?? "firebase";
20939
+ const primaryPlatform = Object.values(appConfigs).find((c) => c.backend !== "none")?.backend ?? "firebase";
20991
20940
  const rootPackageJson = generatePackageJson(
20992
20941
  "consumer-root",
20993
20942
  executionMode,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@donotdev/cli",
3
- "version": "0.0.17",
3
+ "version": "0.0.18",
4
4
  "description": "Command-line interface for DoNotDev Framework",
5
5
  "type": "module",
6
6
  "private": false,
@@ -41,6 +41,14 @@ description: Extract requirements and generate complete HLD through conversation
41
41
 
42
42
  ## Process
43
43
 
44
+ ### Step 0: Start Phase (MANDATORY — DO THIS FIRST)
45
+
46
+ **BEFORE asking any questions or doing any work**, call:
47
+ ```
48
+ start_phase(0)
49
+ ```
50
+ This activates Phase 0: BRAINSTORM and loads the blueprint, persona, context, and lessons learned from previous sessions. **Do NOT proceed without this call.**
51
+
44
52
  ### Step 1: Activate EXTRACTOR Agent
45
53
 
46
54
  **Deploy:** `/agents extractor` (BMAD EXTRACTOR persona)
@@ -87,7 +95,7 @@ EXTRACTOR generates `HLD.md` with:
87
95
 
88
96
  ---
89
97
 
90
- ## Validation Gate
98
+ ## Validation Gate & Phase Completion (MANDATORY)
91
99
 
92
100
  **Before proceeding to `/design`:**
93
101
  - [ ] HLD is complete (no empty sections or TBDs)
@@ -97,6 +105,12 @@ EXTRACTOR generates `HLD.md` with:
97
105
  - [ ] Native vs custom analysis complete
98
106
  - [ ] User has validated HLD
99
107
 
108
+ **When HLD is complete**, write the filled-out spec to `docs/HLD.md` (the template at `guides/wai-way/spec_template.md` stays untouched as reference). Then call:
109
+ ```
110
+ complete_phase({ files: ["docs/HLD.md"], summary: "HLD complete — N entities, N pages, N features" })
111
+ ```
112
+ Then wait for the user to call `approve_phase()` before moving to `/design`.
113
+
100
114
  **Quality Over Speed:** Take as long as needed. A complete HLD that takes 4 hours is better than an incomplete one that takes 20 minutes.
101
115
 
102
116
  ---
@@ -36,6 +36,14 @@ description: Two-agent workflow: Prompt Engineer → Coder (AFTER /design)
36
36
 
37
37
  ## Process
38
38
 
39
+ ### Step 0: Start Phase (MANDATORY — DO THIS FIRST)
40
+
41
+ **BEFORE writing any code**, call:
42
+ ```
43
+ start_phase(3)
44
+ ```
45
+ This activates Phase 3: COMPOSE and loads the blueprint, persona, context, and lessons. **Do NOT write code without this call.**
46
+
39
47
  ### Step 1: Activate FORGER Agent
40
48
 
41
49
  **Deploy:** `/agents builder` (BMAD FORGER persona)
@@ -54,10 +62,19 @@ description: Two-agent workflow: Prompt Engineer → Coder (AFTER /design)
54
62
  - Phase 6: Integration (wire everything together)
55
63
  4. Use framework defaults ONLY (no styling, no customization)
56
64
  5. Hardcode all strings (no i18n yet)
57
- 6. Validate each phase before proceeding
65
+ 6. Run `dndev tc` after every file change — type errors must be fixed immediately
66
+ 7. Validate each phase before proceeding
58
67
 
59
68
  **Output:** Working app (functional MVP, no styling)
60
69
 
70
+ ### Phase Completion (MANDATORY)
71
+
72
+ When all pages are built and `dndev tc` passes, call:
73
+ ```
74
+ complete_phase({ files: ["src/pages/...all page files..."], summary: "N pages composed, all type-checking" })
75
+ ```
76
+ Wait for user to call `approve_phase()` before moving to `/polish`.
77
+
61
78
  ---
62
79
 
63
80
  ## Alternative: Two-Agent Workflow
@@ -79,10 +96,15 @@ For complex builds, you can use:
79
96
  - **Builder (FORGER):** Implements exactly what's in LLD, uses framework defaults only
80
97
  - **Framework defaults ONLY:** No styling, no customization (deferred to /polish)
81
98
  - **Hardcode strings:** No i18n yet (deferred to /polish)
82
- - **MCP required:** Use lookup_symbol for ALL components
83
99
  - **Phase by phase:** Complete each phase before proceeding
84
100
  - **User:** Reviews output, proceeds to /polish when functional
85
101
 
102
+ ## STOP — lookup_symbol Before Every Component (Repeated Here On Purpose)
103
+
104
+ **STOP before writing ANY `@donotdev` import.** Call `lookup_symbol({ symbol: "Name" })` first. Do NOT guess props, hooks, or APIs. Do NOT proceed without verification. `complete_phase` will reject un-looked-up symbols.
105
+
106
+ **Import convention:** Always `@donotdev/<package>` — never sub-paths. No `@donotdev/ui/routing`, no `@donotdev/components/card`. The only exceptions are `@donotdev/core/server`, `@donotdev/core/vite`, `@donotdev/core/next`, `@donotdev/core/functions`.
107
+
86
108
  ## Mode Detection
87
109
 
88
110
  **CRITICAL:** Check working mode first.
@@ -36,6 +36,21 @@ description: Design workflow: Architect → Design Document (BEFORE /build)
36
36
 
37
37
  ## Process
38
38
 
39
+ ### Step 0: Start Phase (MANDATORY — DO THIS FIRST)
40
+
41
+ **BEFORE doing any design work**, call the appropriate phase:
42
+ ```
43
+ start_phase(1) # for SCAFFOLD (routes, page stubs)
44
+ start_phase(2) # for ENTITIES (data models, fields, access)
45
+ ```
46
+ This loads the blueprint, persona, context, and lessons. **Do NOT proceed without this call.**
47
+
48
+ When design work is complete, call:
49
+ ```
50
+ complete_phase({ files: ["...affected files..."], summary: "Description of what was designed" })
51
+ ```
52
+ Wait for user to call `approve_phase()` before moving on.
53
+
39
54
  ### Step 1: Architect Phase
40
55
 
41
56
  **Deploy:** `/agents architect` (WAI-WAY architect role)
@@ -102,6 +117,8 @@ UNRESOLVED:
102
117
  - **ALWAYS reference framework architecture** - stay aligned
103
118
  - **ALWAYS identify impacts** - what breaks if we change this?
104
119
  - **ALWAYS prepare for /build** - design should be actionable
120
+ - **ALWAYS use `lookup_symbol`** when referencing @donotdev components in your design — verify the API exists before putting it in the plan
121
+ - **Import convention:** Always `@donotdev/<package>` top-level, never sub-paths. The only exceptions are `@donotdev/core/server`, `@donotdev/core/vite`, `@donotdev/core/next`, `@donotdev/core/functions`
105
122
 
106
123
  ## Integration with WAI-WAY & BMAD
107
124
 
@@ -42,6 +42,14 @@ description: Generate tests, firestore rules, CI/CD, config, fix bugs, i18n (Pha
42
42
 
43
43
  ## Process
44
44
 
45
+ ### Step 0: Start Phase (MANDATORY — DO THIS FIRST)
46
+
47
+ **BEFORE any polish work**, call:
48
+ ```
49
+ start_phase(4)
50
+ ```
51
+ This activates Phase 4: CONFIGURE and loads the blueprint, persona, context, and lessons. **Do NOT proceed without this call.**
52
+
45
53
  ### Step 1: Activate Polisher Agent
46
54
 
47
55
  **Deploy:** `/agents polisher` (Phase 4 Polisher persona)
@@ -112,6 +120,7 @@ Extract strings to `src/locales/`, replace with `useTranslation()`.
112
120
  ## Ship Readiness
113
121
 
114
122
  App is ready to ship when:
123
+ - ✅ `dndev tc` passes
115
124
  - ✅ `bun test` passes
116
125
  - ✅ `firestore.rules` generated
117
126
  - ✅ `.github/workflows/ci.yml` created
@@ -121,6 +130,14 @@ App is ready to ship when:
121
130
  - ✅ Configuration complete
122
131
  - ✅ (Optional) i18n added
123
132
 
133
+ ## Phase Completion (MANDATORY)
134
+
135
+ When all ship readiness checks pass, call:
136
+ ```
137
+ complete_phase({ files: ["...all test/config files..."], summary: "Tests passing, config complete, ready to ship" })
138
+ ```
139
+ Wait for user to call `approve_phase()`.
140
+
124
141
  ---
125
142
 
126
143
  ## Next Step