create-sdd-project 0.17.1 → 0.17.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/lib/scanner.js +54 -18
  2. package/package.json +1 -1
package/lib/scanner.js CHANGED
@@ -8,18 +8,36 @@ const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', '.n
8
8
  /**
9
9
  * Scan an existing project directory and return detected configuration.
10
10
  *
11
- * v0.17.1: monorepo-aware. If the root `package.json` does not yield a
12
- * backend/frontend detection AND the project is a monorepo with
13
- * `package.json#workspaces`, enumerate workspace `package.json` files in
14
- * declaration order (pattern outer, lexical inner, deduped by normalized
15
- * path) and run `detectBackend` / `detectFrontend` per workspace. The
16
- * FIRST workspace returning `detected: true` wins and its result is merged
11
+ * v0.17.1: monorepo-aware. If the project is a monorepo with
12
+ * `package.json#workspaces` and the root `package.json` does not yield a
13
+ * complete backend/frontend detection, enumerate workspace `package.json`
14
+ * files in declaration order (pattern outer, lexical inner, deduped by
15
+ * normalized path) and run `detectBackend` / `detectFrontend` per workspace.
16
+ * The FIRST workspace returning a framework wins and its result is merged
17
17
  * into `result.backend` / `result.frontend` with a `workspaceSource` field
18
18
  * recording the detected workspace's relative path (for diagnostics).
19
19
  *
20
- * Scanner additive invariant (v0.17.1): for single-package projects, or
21
- * monorepos where root detection already succeeded, the workspace
22
- * enumeration never fires and the result is byte-identical to v0.17.0.
20
+ * v0.17.2: the "complete detection" gate uses `framework` presence, not
21
+ * the older `detected` flag. This is because `detectBackend` has a
22
+ * partial-detection fallback (see `detectBackend` lines ~259-261) that
23
+ * sets `detected: true` when only `db` or `orm` is found — commonly
24
+ * triggered by a ROOT `.env.example` declaring `DATABASE_URL` + `PORT`
25
+ * in a monorepo whose real backend stack lives under `packages/api`.
26
+ * Under the v0.17.1 guard, that partial detection blocked the workspace
27
+ * enumeration and left `backend.framework` null → `adaptBackendStandards`
28
+ * produced generic placeholders → `adaptAgentsMd` fell back to the
29
+ * `(DDD, Express, Prisma)` template literal. Gating on `!framework`
30
+ * fires the enumeration in that case and correctly promotes
31
+ * workspace-level framework/orm info while preserving root-level
32
+ * env-derived fields (`db`, `port`) that the workspace didn't detect.
33
+ *
34
+ * Scanner additive invariant: for single-package projects, `isMonorepo`
35
+ * is false and the enumeration block is skipped entirely — same behavior
36
+ * as v0.17.0 and v0.17.1, byte-identical output. For monorepos, the
37
+ * v0.17.2 gate is strictly looser than v0.17.1's, so it runs the
38
+ * enumeration in a strict superset of cases. Enumeration only adds
39
+ * info (framework/orm from workspace), never removes it. Therefore
40
+ * v0.17.2 scan output ⊇ v0.17.1 scan output for the same input.
23
41
  */
24
42
  function scan(projectDir) {
25
43
  const pkg = readPackageJson(projectDir);
@@ -28,25 +46,43 @@ function scan(projectDir) {
28
46
  const frontend = detectFrontend(projectDir, pkg);
29
47
  const isMonorepo = detectMonorepo(projectDir, pkg);
30
48
 
31
- // v0.17.1 monorepo fallback
32
- if (isMonorepo && (!backend.detected || !frontend.detected)) {
49
+ // v0.17.2 monorepo fallback: promote to workspace when root lacks a
50
+ // framework, even if root partial detection set `detected: true`.
51
+ if (isMonorepo && (!backend.framework || !frontend.framework)) {
33
52
  const workspaces = enumerateWorkspaces(projectDir, pkg);
34
53
  for (const wsRel of workspaces) {
35
54
  const wsAbs = path.join(projectDir, ...wsRel.split('/'));
36
55
  const wsPkg = readPackageJson(wsAbs);
37
- if (!backend.detected) {
56
+ if (!backend.framework) {
38
57
  const wsBackend = detectBackend(wsAbs, wsPkg);
39
- if (wsBackend.detected) {
40
- Object.assign(backend, wsBackend, { workspaceSource: wsRel });
58
+ if (wsBackend.framework) {
59
+ // Field-merge: prefer workspace values for fields it detected,
60
+ // preserve root values for fields the workspace didn't (e.g.,
61
+ // a root .env's DATABASE_URL → root.db, which packages/api
62
+ // might not repeat in its own .env). Iterate `Object.keys` so
63
+ // future additions to `detectBackend` are forwarded without
64
+ // requiring a dual-update here (Gemini round-4 finding 1).
65
+ // `workspaceSource` records the winning workspace for diagnostics.
66
+ for (const field of Object.keys(wsBackend)) {
67
+ if (wsBackend[field] !== null && wsBackend[field] !== undefined) {
68
+ backend[field] = wsBackend[field];
69
+ }
70
+ }
71
+ backend.workspaceSource = wsRel;
41
72
  }
42
73
  }
43
- if (!frontend.detected) {
74
+ if (!frontend.framework) {
44
75
  const wsFrontend = detectFrontend(wsAbs, wsPkg);
45
- if (wsFrontend.detected) {
46
- Object.assign(frontend, wsFrontend, { workspaceSource: wsRel });
76
+ if (wsFrontend.framework) {
77
+ for (const field of Object.keys(wsFrontend)) {
78
+ if (wsFrontend[field] !== null && wsFrontend[field] !== undefined) {
79
+ frontend[field] = wsFrontend[field];
80
+ }
81
+ }
82
+ frontend.workspaceSource = wsRel;
47
83
  }
48
84
  }
49
- if (backend.detected && frontend.detected) break;
85
+ if (backend.framework && frontend.framework) break;
50
86
  }
51
87
  }
52
88
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-sdd-project",
3
- "version": "0.17.1",
3
+ "version": "0.17.2",
4
4
  "description": "Create a new SDD DevFlow project with AI-assisted development workflow",
5
5
  "bin": {
6
6
  "create-sdd-project": "bin/cli.js"