@donotdev/cli 0.0.13 → 0.0.14

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 (32) hide show
  1. package/dependencies-matrix.json +2 -2
  2. package/dist/bin/commands/agent-setup.d.ts +6 -0
  3. package/dist/bin/commands/agent-setup.d.ts.map +1 -0
  4. package/dist/bin/commands/agent-setup.js +623 -0
  5. package/dist/bin/commands/agent-setup.js.map +1 -0
  6. package/dist/bin/commands/build.js +13 -12
  7. package/dist/bin/commands/bump.js +70 -28
  8. package/dist/bin/commands/cacheout.js +13 -12
  9. package/dist/bin/commands/create-app.js +53 -151
  10. package/dist/bin/commands/create-project.js +72 -166
  11. package/dist/bin/commands/deploy.js +16 -15
  12. package/dist/bin/commands/dev.js +13 -12
  13. package/dist/bin/commands/emu.js +13 -12
  14. package/dist/bin/commands/format.js +13 -12
  15. package/dist/bin/commands/lint.js +13 -12
  16. package/dist/bin/commands/preview.js +13 -12
  17. package/dist/bin/commands/sync-secrets.js +13 -12
  18. package/dist/bin/commands/wai.js +7397 -11
  19. package/dist/index.js +74 -55
  20. package/package.json +1 -1
  21. package/templates/root-consumer/.claude/commands/brainstorm.md.example +1 -1
  22. package/templates/root-consumer/.claude/commands/build.md.example +1 -1
  23. package/templates/root-consumer/.claude/commands/design.md.example +1 -1
  24. package/templates/root-consumer/.claude/commands/polish.md.example +1 -1
  25. package/templates/root-consumer/.dndev/args.json.example +6 -0
  26. package/templates/root-consumer/.gemini/settings.json.example +2 -2
  27. package/templates/root-consumer/AI.md.example +25 -14
  28. package/templates/root-consumer/CLAUDE.md.example +10 -4
  29. package/templates/root-consumer/guides/dndev/AGENT_START_HERE.md.example +34 -0
  30. package/templates/root-consumer/guides/dndev/GOTCHAS.md.example +186 -0
  31. package/templates/root-consumer/guides/dndev/INDEX.md.example +1 -0
  32. package/templates/root-consumer/guides/dndev/SETUP_FUNCTIONS.md.example +12 -7
package/dist/index.js CHANGED
@@ -2214,7 +2214,7 @@ var require_parse = __commonJS({
2214
2214
  CHAR_NO_BREAK_SPACE,
2215
2215
  CHAR_ZERO_WIDTH_NOBREAK_SPACE
2216
2216
  } = require_constants();
2217
- var parse = (input, options = {}) => {
2217
+ var parse2 = (input, options = {}) => {
2218
2218
  if (typeof input !== "string") {
2219
2219
  throw new TypeError("Expected a string");
2220
2220
  }
@@ -2414,7 +2414,7 @@ var require_parse = __commonJS({
2414
2414
  push({ type: "eos" });
2415
2415
  return ast;
2416
2416
  };
2417
- module.exports = parse;
2417
+ module.exports = parse2;
2418
2418
  }
2419
2419
  });
2420
2420
 
@@ -2426,7 +2426,7 @@ var require_braces = __commonJS({
2426
2426
  var stringify2 = require_stringify();
2427
2427
  var compile = require_compile();
2428
2428
  var expand = require_expand();
2429
- var parse = require_parse();
2429
+ var parse2 = require_parse();
2430
2430
  var braces = (input, options = {}) => {
2431
2431
  let output = [];
2432
2432
  if (Array.isArray(input)) {
@@ -2446,7 +2446,7 @@ var require_braces = __commonJS({
2446
2446
  }
2447
2447
  return output;
2448
2448
  };
2449
- braces.parse = (input, options = {}) => parse(input, options);
2449
+ braces.parse = (input, options = {}) => parse2(input, options);
2450
2450
  braces.stringify = (input, options = {}) => {
2451
2451
  if (typeof input === "string") {
2452
2452
  return stringify2(braces.parse(input, options), options);
@@ -3103,7 +3103,7 @@ var require_parse2 = __commonJS({
3103
3103
  var syntaxError = (type, char) => {
3104
3104
  return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`;
3105
3105
  };
3106
- var parse = (input, options) => {
3106
+ var parse2 = (input, options) => {
3107
3107
  if (typeof input !== "string") {
3108
3108
  throw new TypeError("Expected a string");
3109
3109
  }
@@ -3252,7 +3252,7 @@ var require_parse2 = __commonJS({
3252
3252
  output = token.close = `)$))${extglobStar}`;
3253
3253
  }
3254
3254
  if (token.inner.includes("*") && (rest = remaining()) && /^\.[^\\/.]+$/.test(rest)) {
3255
- const expression = parse(rest, { ...options, fastpaths: false }).output;
3255
+ const expression = parse2(rest, { ...options, fastpaths: false }).output;
3256
3256
  output = token.close = `)${expression})${extglobStar})`;
3257
3257
  }
3258
3258
  if (token.prev.type === "bos") {
@@ -3777,7 +3777,7 @@ var require_parse2 = __commonJS({
3777
3777
  }
3778
3778
  return state;
3779
3779
  };
3780
- parse.fastpaths = (input, options) => {
3780
+ parse2.fastpaths = (input, options) => {
3781
3781
  const opts = { ...options };
3782
3782
  const max = typeof opts.maxLength === "number" ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
3783
3783
  const len = input.length;
@@ -3843,7 +3843,7 @@ var require_parse2 = __commonJS({
3843
3843
  }
3844
3844
  return source;
3845
3845
  };
3846
- module.exports = parse;
3846
+ module.exports = parse2;
3847
3847
  }
3848
3848
  });
3849
3849
 
@@ -3854,7 +3854,7 @@ var require_picomatch = __commonJS({
3854
3854
  init_utils();
3855
3855
  var path = __require("path");
3856
3856
  var scan = require_scan();
3857
- var parse = require_parse2();
3857
+ var parse2 = require_parse2();
3858
3858
  var utils = require_utils2();
3859
3859
  var constants2 = require_constants2();
3860
3860
  var isObject = (val) => val && typeof val === "object" && !Array.isArray(val);
@@ -3942,7 +3942,7 @@ var require_picomatch = __commonJS({
3942
3942
  picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str);
3943
3943
  picomatch.parse = (pattern, options) => {
3944
3944
  if (Array.isArray(pattern)) return pattern.map((p2) => picomatch.parse(p2, options));
3945
- return parse(pattern, { ...options, fastpaths: false });
3945
+ return parse2(pattern, { ...options, fastpaths: false });
3946
3946
  };
3947
3947
  picomatch.scan = (input, options) => scan(input, options);
3948
3948
  picomatch.compileRe = (state, options, returnOutput = false, returnState = false) => {
@@ -3968,10 +3968,10 @@ var require_picomatch = __commonJS({
3968
3968
  }
3969
3969
  let parsed = { negated: false, fastpaths: true };
3970
3970
  if (options.fastpaths !== false && (input[0] === "." || input[0] === "*")) {
3971
- parsed.output = parse.fastpaths(input, options);
3971
+ parsed.output = parse2.fastpaths(input, options);
3972
3972
  }
3973
3973
  if (!parsed.output) {
3974
- parsed = parse(input, options);
3974
+ parsed = parse2(input, options);
3975
3975
  }
3976
3976
  return picomatch.compileRe(parsed, options, returnOutput, returnState);
3977
3977
  };
@@ -7959,6 +7959,7 @@ __export(pathResolver_exports, {
7959
7959
  ensureDirSync: () => ensureDirSync,
7960
7960
  findFiles: () => findFiles,
7961
7961
  findNodeModulesDir: () => findNodeModulesDir,
7962
+ findPackageRootUp: () => findPackageRootUp,
7962
7963
  fromAppRoot: () => fromAppRoot,
7963
7964
  getAppRoot: () => getAppRoot,
7964
7965
  getBasename: () => getBasename,
@@ -7975,7 +7976,6 @@ __export(pathResolver_exports, {
7975
7976
  getRelativePathBetween: () => getRelativePathBetween,
7976
7977
  getRepoRoot: () => getRepoRoot,
7977
7978
  getTemplatesRoot: () => getTemplatesRoot,
7978
- getToolingPath: () => getToolingPath,
7979
7979
  glob: () => glob,
7980
7980
  globSync: () => globSync,
7981
7981
  isAbsolute: () => isAbsolute,
@@ -8014,6 +8014,7 @@ import {
8014
8014
  extname as extname2,
8015
8015
  relative as relative2,
8016
8016
  resolve as resolve2,
8017
+ parse,
8017
8018
  isAbsolute as pathIsAbsolute
8018
8019
  } from "node:path";
8019
8020
  import { fileURLToPath as fileURLToPath2 } from "node:url";
@@ -8070,37 +8071,19 @@ function getBinPath(binaryName) {
8070
8071
  }
8071
8072
  return binaryName;
8072
8073
  }
8073
- function getToolingPath() {
8074
- const mode = detectExecutionMode();
8075
- if (mode === "development") {
8076
- const repoRoot = getRepoRoot();
8077
- const packagesToolingPath = normalizePath(repoRoot, PACKAGE_PATHS.TOOLING);
8078
- if (pathExists(packagesToolingPath)) {
8079
- return normalizePath(packagesToolingPath);
8080
- }
8081
- }
8082
- throw new DoNotDevError(
8083
- "Could not find tooling package. This function is only available in development mode.",
8084
- "path-resolution-error"
8085
- );
8086
- }
8087
8074
  function detectExecutionMode() {
8088
- const currentDir = process.cwd();
8089
- const toolingPath = joinPath(currentDir, PACKAGE_PATHS.TOOLING);
8090
- if (pathExists(toolingPath)) {
8091
- return "development";
8092
- }
8093
8075
  const fileUrlPath = new URL(import.meta.url).pathname;
8094
- if (fileUrlPath.includes("node_modules/@donotdev/cli")) {
8095
- return "published";
8076
+ if (!fileUrlPath.includes("node_modules")) {
8077
+ return "development";
8096
8078
  }
8097
8079
  return "published";
8098
8080
  }
8099
8081
  function getTemplatesRoot() {
8100
8082
  const mode = detectExecutionMode();
8101
8083
  if (mode === "development") {
8102
- const repoRoot = getRepoRoot();
8103
- return normalizePath(repoRoot, PACKAGE_PATHS.CLI, "templates");
8084
+ const fileUrlPath = new URL(import.meta.url).pathname;
8085
+ const frameworkRoot = normalizePath(dirname2(fileUrlPath), "../../../..");
8086
+ return normalizePath(frameworkRoot, PACKAGE_PATHS.CLI, "templates");
8104
8087
  } else {
8105
8088
  try {
8106
8089
  const cliRoot2 = resolveFrameworkPackage("@donotdev/cli");
@@ -8122,10 +8105,43 @@ function getTemplatesRoot() {
8122
8105
  }
8123
8106
  } catch {
8124
8107
  }
8108
+ try {
8109
+ const currentScriptDir = getDirnameFromUrl(import.meta.url);
8110
+ const packageRoot = findPackageRootUp(currentScriptDir, "@donotdev/cli");
8111
+ if (packageRoot) {
8112
+ const templatesPath = normalizePath(packageRoot, "templates");
8113
+ if (pathExists(templatesPath)) {
8114
+ return templatesPath;
8115
+ }
8116
+ }
8117
+ } catch {
8118
+ }
8125
8119
  const cliRoot = getCliRootFromBundle();
8126
8120
  return normalizePath(cliRoot, "templates");
8127
8121
  }
8128
8122
  }
8123
+ function findPackageRootUp(startDir, packageName) {
8124
+ let currentDir = normalizePath(startDir);
8125
+ const root = parse(currentDir).root;
8126
+ const fs2 = createRequire2(import.meta.url)("node:fs");
8127
+ while (currentDir !== root) {
8128
+ const packageJsonPath = joinPath(currentDir, "package.json");
8129
+ if (fs2.existsSync(packageJsonPath)) {
8130
+ try {
8131
+ const content = fs2.readFileSync(packageJsonPath, "utf8");
8132
+ const pkg = JSON.parse(content);
8133
+ if (pkg.name === packageName) {
8134
+ return currentDir;
8135
+ }
8136
+ } catch {
8137
+ }
8138
+ }
8139
+ const parentDir = getDirname(currentDir);
8140
+ if (parentDir === currentDir) break;
8141
+ currentDir = parentDir;
8142
+ }
8143
+ return null;
8144
+ }
8129
8145
  function getCliRootFromBundle() {
8130
8146
  const currentDir = getDirnameFromUrl(import.meta.url);
8131
8147
  return normalizePath(currentDir, "..", "..", "..");
@@ -8245,7 +8261,6 @@ var init_pathResolver = __esm({
8245
8261
  "use strict";
8246
8262
  init_utils();
8247
8263
  init_PathResolver();
8248
- init_errors();
8249
8264
  pathResolverInstance = PathResolver.getInstance({ debug: false });
8250
8265
  getPathResolver = (options) => PathResolver.getInstance(options);
8251
8266
  getRepoRoot = () => pathResolverInstance.getRepoRoot();
@@ -15606,7 +15621,7 @@ var require_public_api = __commonJS({
15606
15621
  }
15607
15622
  return doc;
15608
15623
  }
15609
- function parse(src, reviver, options) {
15624
+ function parse2(src, reviver, options) {
15610
15625
  let _reviver = void 0;
15611
15626
  if (typeof reviver === "function") {
15612
15627
  _reviver = reviver;
@@ -15647,7 +15662,7 @@ var require_public_api = __commonJS({
15647
15662
  return value.toString(options);
15648
15663
  return new Document.Document(value, _replacer, options).toString(options);
15649
15664
  }
15650
- exports.parse = parse;
15665
+ exports.parse = parse2;
15651
15666
  exports.parseAllDocuments = parseAllDocuments;
15652
15667
  exports.parseDocument = parseDocument;
15653
15668
  exports.stringify = stringify2;
@@ -15849,7 +15864,7 @@ async function askForInput(message, defaultValue = "") {
15849
15864
  const result = await he({
15850
15865
  message,
15851
15866
  placeholder: defaultValue || void 0,
15852
- initialValue: defaultValue || void 0
15867
+ defaultValue: defaultValue || void 0
15853
15868
  });
15854
15869
  if (pD(result)) {
15855
15870
  xe("Operation cancelled.");
@@ -19578,9 +19593,6 @@ async function main9(options) {
19578
19593
  log.info(
19579
19594
  `Creating project "${projectName}" with ${appNames.length} app(s): ${appNames.join(", ")}`
19580
19595
  );
19581
- let needsAuth = false;
19582
- let needsOAuth = false;
19583
- let needsBilling = false;
19584
19596
  for (const appName of appNames) {
19585
19597
  if (!appConfigs[appName]) {
19586
19598
  log.warn(`Missing config for app "${appName}", using defaults`);
@@ -19664,9 +19676,12 @@ async function main9(options) {
19664
19676
  firebaseSecretName: projectName.toUpperCase().replace(/-/g, "_"),
19665
19677
  YOUR_FIREBASE_PROJECT_ID: firebaseProjectId,
19666
19678
  YOUR_REGION: firebaseRegion,
19667
- needsAuth,
19668
- needsOAuth,
19669
- needsBilling
19679
+ needsAuth: false,
19680
+ // Determined by agent in WAI-WAY Phase 0
19681
+ needsOAuth: false,
19682
+ // Determined by agent in WAI-WAY Phase 0
19683
+ needsBilling: false
19684
+ // Determined by agent in WAI-WAY Phase 0
19670
19685
  };
19671
19686
  const firebaseRootFiles = /* @__PURE__ */ new Set([
19672
19687
  "firebase.json.example",
@@ -19722,9 +19737,9 @@ async function main9(options) {
19722
19737
  }
19723
19738
  const relativeMonorepoPath = executionMode === "development" ? calculateRelativePath(projectDirNormalized, monorepoRoot) : "../../packages/tooling";
19724
19739
  await mergeRootPackageJson(projectDirNormalized, allAppNames, {
19725
- needsAuth,
19726
- needsOAuth,
19727
- needsBilling,
19740
+ needsAuth: false,
19741
+ needsOAuth: false,
19742
+ needsBilling: false,
19728
19743
  monorepoRelativePath: relativeMonorepoPath
19729
19744
  });
19730
19745
  await mergeRootTsConfig(
@@ -19808,14 +19823,18 @@ async function main9(options) {
19808
19823
  Me(
19809
19824
  `1. ${cdCommand}
19810
19825
  2. bun install
19811
- 3. Open the project in your IDE (Cursor, VS Code, etc.)
19812
- 4. Tell your AI agent: "Read AI.md and build my app"
19826
+ 3. Open the project in your IDE
19827
+ 4. Tell your AI agent:
19828
+
19829
+ "Read AI.md and build my app"
19830
+
19831
+ The AI agent will use the MCP server automatically.
19832
+ It handles everything: spec, scaffold, entities, pages.
19813
19833
 
19814
- That's it. The agent handles the rest.
19834
+ Cursor users: enable MCP in Settings > Tools & MCP > toggle "donotdev" ON
19835
+ Claude Code / Windsurf: MCP auto-connects, nothing to do
19815
19836
 
19816
- ` + (anyAppNeedsBackend ? `Dev server: dndev dev | With emulators: dndev emu
19817
- ` : `Dev server: dndev dev
19818
- `) + `AI setup: dndev agent (re-configure MCP if needed)`,
19837
+ ` + (anyAppNeedsBackend ? `Dev server: dndev dev | With emulators: dndev emu` : `Dev server: dndev dev`),
19819
19838
  "\u{1F4CB} Next Steps"
19820
19839
  );
19821
19840
  } catch (error2) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@donotdev/cli",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
4
4
  "description": "Command-line interface for DoNotDev Framework",
5
5
  "type": "module",
6
6
  "private": false,
@@ -6,7 +6,7 @@ description: Extract requirements and generate complete HLD through conversation
6
6
 
7
7
  **⚠️ MODE CHECK:** This command is for **Consumer App Development** only.
8
8
 
9
- **If you're in the framework monorepo (`c:\ws\dndev`):**
9
+ **If you're in the framework monorepo (this repo):**
10
10
  - ❌ **DO NOT use `/brainstorm`** - framework dev doesn't need requirements extraction
11
11
  - ✅ See [Modes Guide](https://github.com/donotdev/framework/blob/main/docs/development/MODES.md) for framework dev workflow
12
12
 
@@ -6,7 +6,7 @@ description: Two-agent workflow: Prompt Engineer → Coder (AFTER /design)
6
6
 
7
7
  **⚠️ MODE CHECK:** This command is for **Consumer App Development** only.
8
8
 
9
- **If you're in the framework monorepo (`c:\ws\dndev`):**
9
+ **If you're in the framework monorepo (this repo):**
10
10
  - ❌ **DO NOT use `/build`** - code directly in `packages/*/src/`
11
11
  - ✅ Use direct coding following Architecture Hub patterns
12
12
  - ✅ See [Modes Guide](https://github.com/donotdev/framework/blob/main/docs/development/MODES.md) for framework dev workflow
@@ -6,7 +6,7 @@ description: Design workflow: Architect → Design Document (BEFORE /build)
6
6
 
7
7
  **⚠️ MODE CHECK:** This command is for **Consumer App Development** only.
8
8
 
9
- **If you're in the framework monorepo (`c:\ws\dndev`):**
9
+ **If you're in the framework monorepo (this repo):**
10
10
  - ❌ **DO NOT use `/design`** - design directly, then code in `packages/*/src/`
11
11
  - ✅ Use Architecture Hub + Development Hub for framework design patterns
12
12
  - ✅ See [Modes Guide](https://github.com/donotdev/framework/blob/main/docs/development/MODES.md) for framework dev workflow
@@ -6,7 +6,7 @@ description: Generate tests, firestore rules, CI/CD, config, fix bugs, i18n (Pha
6
6
 
7
7
  **⚠️ MODE CHECK:** This command is for **Consumer App Development** only.
8
8
 
9
- **If you're in the framework monorepo (`c:\ws\dndev`):**
9
+ **If you're in the framework monorepo (this repo):**
10
10
  - ❌ **DO NOT use `/polish`** - framework dev doesn't use this workflow
11
11
  - ✅ See [Modes Guide](https://github.com/donotdev/framework/blob/main/docs/development/MODES.md) for framework dev workflow
12
12
 
@@ -0,0 +1,6 @@
1
+ {
2
+ "platform": "firebase",
3
+ "strictness": "enforced",
4
+ "features": ["crud", "auth", "i18n", "billing", "oauth", "functions"],
5
+ "region": "europe-west1"
6
+ }
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "mcpServers": {
3
3
  "donotdev": {
4
- "command": "npx",
5
- "args": ["-y", "@donotdev/mcp-server@latest"],
4
+ "command": "bunx",
5
+ "args": ["@donotdev/mcp-server"],
6
6
  "trust": true
7
7
  }
8
8
  }
@@ -4,9 +4,11 @@
4
4
 
5
5
  ## What To Do Right Now
6
6
 
7
- 1. **Check environment setup first.** Ask the user: "Have you completed the setup steps on the homepage? (Run `bun dev` and open the app to see them.) You need Git, Firebase, and .env configured before we start building." If they haven't, coach them through each step on the homepage — Git repo, Firebase project, service account key, environment variables. Don't start coding until Firebase is configured and `dndev emu start` works.
8
- 2. Read `guides/wai-way/WAI_WAY_CLI.md` the complete workflow
9
- 3. Start with **Phase 0: BRAINSTORM** ask the user what they want to build
7
+ 1. **Verify MCP is working.** Try calling `list_features()`. If it works, you're good. If not:
8
+ - **Cursor:** Settings → Tools & MCP → toggle "donotdev" ON. MCP only works in Composer mode (`Cmd/Ctrl+I`).
9
+ - **Claude Code / Windsurf:** Auto-connects from `.mcp.json`. If broken, check `bun` is in PATH.
10
+ 2. **Check environment setup.** Ask the user: "Have you run `bun install`? Run `dndev dev` and open the app — the homepage has setup steps for Git, Firebase, and .env."
11
+ 3. Call `start_phase(0)` — begin **Phase 0: BRAINSTORM**
10
12
  4. Follow each phase in order. Do not skip phases.
11
13
 
12
14
  ## Environment Variables — Where They Go
@@ -73,21 +75,25 @@ node_modules/@donotdev/core/dist/index.d.ts → Core utilities
73
75
 
74
76
  ## Supported IDEs
75
77
 
76
- DoNotDev + WAI-WAY is designed for **MCP-capable AI IDEs**. MCP is what gives the AI agent real TypeScript types instead of hallucinated props.
78
+ MCP gives the AI agent real TypeScript types instead of hallucinated props. Config files are auto-created by `dndev init`.
77
79
 
78
- | IDE | MCP Support | Config File |
79
- |-----|-------------|-------------|
80
- | **Cursor** | Full | `.cursor/mcp.json` (auto-configured) |
81
- | **Claude Code** | Full | `.mcp.json` (auto-configured) |
82
- | **Windsurf** | Full | `.mcp.json` (auto-configured) |
83
- | **AntiGravity** | Full | `.mcp.json` (auto-configured) |
84
- | **Gemini** | Full | `.gemini/settings.json` (auto-configured) |
80
+ | IDE | Config | Setup |
81
+ |-----|--------|-------|
82
+ | **Claude Code** | `.mcp.json` | Auto-connects. Nothing to do. |
83
+ | **Windsurf** | `.mcp.json` | Auto-connects. Nothing to do. |
84
+ | **Cursor** | `.cursor/mcp.json` | Settings → Tools & MCP → toggle "donotdev" ON. **MCP only works in Composer mode** (`Cmd/Ctrl+I`). |
85
+ | **Gemini CLI** | `.gemini/settings.json` | Auto-connects. Nothing to do. |
85
86
 
86
- **Without MCP (ChatGPT, Copilot, etc.):** The workflow still works — read blueprints directly from `guides/wai-way/blueprints/` and look up types manually from `.d.ts` files. You lose symbol tracking and convention enforcement, but the phase structure and entity-driven patterns remain.
87
+ **If MCP tools aren't available**, guide the user:
88
+ 1. Check `bun` is in PATH (`which bun`)
89
+ 2. **Cursor:** Must be in Composer mode (`Cmd/Ctrl+I`) and server toggled ON
90
+ 3. Check MCP logs: `Cmd/Ctrl+Shift+U` → Output → "MCP Logs"
87
91
 
88
- ## MCP Tools (9 Pre-Configured)
92
+ **Without MCP (ChatGPT, Copilot, etc.):** Read blueprints from `guides/wai-way/blueprints/` and types from `node_modules/@donotdev/*/dist/*.d.ts`. You lose symbol tracking and convention enforcement.
89
93
 
90
- MCP is configured in `.mcp.json` / `.cursor/mcp.json` / `.gemini/settings.json`. Your IDE connects automatically.
94
+ ## MCP Tools (13 Pre-Configured)
95
+
96
+ MCP config files are auto-created in `.mcp.json` / `.cursor/mcp.json` / `.gemini/settings.json`. **You must enable the server in your IDE settings** (see "Supported IDEs" above). Once enabled, your IDE connects automatically.
91
97
 
92
98
  | Tool | What It Does |
93
99
  |------|-------------|
@@ -99,7 +105,12 @@ MCP is configured in `.mcp.json` / `.cursor/mcp.json` / `.gemini/settings.json`.
99
105
  | `get_guide("CRUD")` | Fetch framework setup guides |
100
106
  | `get_guideline("styling:colors")` | Fetch architecture guidelines (supports sections) |
101
107
  | `search_framework("keyword")` | Search across all guides and type definitions |
108
+ | `list_features()` | List all framework packages with summaries |
102
109
  | `record_lesson("text")` | Save to project memory (returned on next start_phase) |
110
+ | `init_implementation({ from_spec: true })` | Create `.dndev/implementation.md` to track progress |
111
+ | `update_progress({ item: "...", done: true })` | Tick/untick items in implementation checklist |
112
+ | `get_progress()` | Read implementation progress stats |
113
+ | `get_project_history()` | Get captain's log with full session history |
103
114
 
104
115
  ## Convention Enforcement
105
116
 
@@ -17,7 +17,7 @@
17
17
  - **Creating with framework** (Mode 3): Build new app features
18
18
  - **Tweaking framework app** (Mode 4): Modify existing app features
19
19
 
20
- **CLI:** `dndev` (public CLI, installed globally)
20
+ **CLI:** `dndev` (public CLI, installed globally via `npm install -g @donotdev/cli`)
21
21
 
22
22
  **Workflow:**
23
23
  1. `/design [requirement]` → Architect designs solution
@@ -29,7 +29,7 @@
29
29
  **⚠️ IMPORTANT:**
30
30
  - Use ONLY published `@donotdev/*` packages
31
31
  - Cannot modify framework internals
32
- - If framework needs changes, work in monorepo (`c:\ws\dndev`)
32
+ - If framework needs changes, work in the framework monorepo (this repo)
33
33
 
34
34
  ---
35
35
 
@@ -116,13 +116,19 @@ If MCP tools unavailable → STOP and tell user to enable MCP.
116
116
  - `get_guideline` — fetch architecture guidelines
117
117
  - `search_framework` — search across all guides and symbols
118
118
 
119
+ ## Project Args & Gotchas
120
+
121
+ - **`.dndev/args.json`** — Per-project config (platform, strictness, features, region). All features ON by default. Phase 0 narrows down. Edit `strictness` to control validation: `enforced` (default) | `warnings` | `permissive`.
122
+ - **`guides/dndev/GOTCHAS.md`** — Common mistakes, phase-tagged. Read directly or loaded by MCP `start_phase()`.
123
+ - **Without MCP:** Both files are plain JSON/markdown — any agent reads them directly. MCP automates filtering + enforcement but is not required.
124
+
119
125
  ## WAI-WAY Workflow
120
126
 
121
127
  **Read `AI.md` at the project root for the full workflow.**
122
128
 
123
129
  For each phase (0=BRAINSTORM, 1=SCAFFOLD, 2=ENTITIES, 3=COMPOSE, 4=CONFIGURE):
124
130
 
125
- 1. `mcp:start_phase(N)` — returns blueprint, context, and lessons
131
+ 1. `mcp:start_phase(N)` — returns blueprint, context, lessons, project args, and phase-relevant gotchas
126
132
  2. Work — follow blueprint, call `lookup_symbol` before using any component
127
- 3. `mcp:complete_phase({ files })` — validates conventions + symbol usage, submits for review
133
+ 3. `mcp:complete_phase({ files })` — validates conventions + symbol usage (respects `strictness`), submits for review
128
134
  4. `mcp:approve_phase()` — user approves, phase is done
@@ -63,4 +63,38 @@ Check that the user has completed environment setup:
63
63
 
64
64
  If not, coach them: "Run `dndev firebase:setup` first, then follow the prompts." See [SETUP_FIREBASE.md](./SETUP_FIREBASE.md).
65
65
 
66
+ ---
67
+
68
+ ## Project Args (`.dndev/args.json`)
69
+
70
+ Generated by `dndev init`. All features ON by default — Phase 0 narrows down based on what the user actually needs.
71
+
72
+ ```json
73
+ {
74
+ "platform": "firebase",
75
+ "strictness": "enforced",
76
+ "features": ["crud", "auth", "i18n", "billing", "oauth", "functions"],
77
+ "region": "europe-west1"
78
+ }
79
+ ```
80
+
81
+ | Field | Values | Effect |
82
+ |-------|--------|--------|
83
+ | `platform` | `firebase`, `vercel` | Derived from builder choice |
84
+ | `strictness` | `enforced`, `warnings`, `permissive` | `enforced` = blocks `complete_phase` on convention violations. `warnings` = reports but allows. `permissive` = skips checks. |
85
+ | `features` | `crud`, `auth`, `i18n`, `billing`, `oauth`, `functions` | Filters gotchas — remove features the project doesn't use to reduce noise |
86
+ | `region` | any GCP region | Informational, shown in `start_phase` context |
87
+
88
+ `start_phase()` returns project args + phase-relevant gotchas automatically. `complete_phase()` respects `strictness`.
89
+
90
+ **Without MCP:** `args.json` and `GOTCHAS.md` are plain files. Any agent can read them directly.
91
+
92
+ ---
93
+
94
+ ## Gotchas (`guides/dndev/GOTCHAS.md`)
95
+
96
+ Common mistakes, phase-tagged. `start_phase(N)` automatically filters and returns only the gotchas relevant to phase N and your enabled features. Read the full file for reference: [GOTCHAS.md](../guides/dndev/GOTCHAS.md).
97
+
98
+ ---
99
+
66
100
  **Starting:** Call `list_features()` first, then `get_phase_status()` to see where you are, then `start_phase(0)` to begin.