@zigrivers/scaffold 3.9.2 → 3.10.1

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 (214) hide show
  1. package/README.md +39 -8
  2. package/dist/cli/commands/adopt.cli-flags.test.d.ts +2 -0
  3. package/dist/cli/commands/adopt.cli-flags.test.d.ts.map +1 -0
  4. package/dist/cli/commands/adopt.cli-flags.test.js +165 -0
  5. package/dist/cli/commands/adopt.cli-flags.test.js.map +1 -0
  6. package/dist/cli/commands/adopt.config-resolution.test.d.ts +2 -0
  7. package/dist/cli/commands/adopt.config-resolution.test.d.ts.map +1 -0
  8. package/dist/cli/commands/adopt.config-resolution.test.js +217 -0
  9. package/dist/cli/commands/adopt.config-resolution.test.js.map +1 -0
  10. package/dist/cli/commands/adopt.config-write-integration.test.d.ts +2 -0
  11. package/dist/cli/commands/adopt.config-write-integration.test.d.ts.map +1 -0
  12. package/dist/cli/commands/adopt.config-write-integration.test.js +138 -0
  13. package/dist/cli/commands/adopt.config-write-integration.test.js.map +1 -0
  14. package/dist/cli/commands/adopt.d.ts +4 -0
  15. package/dist/cli/commands/adopt.d.ts.map +1 -1
  16. package/dist/cli/commands/adopt.js +432 -61
  17. package/dist/cli/commands/adopt.js.map +1 -1
  18. package/dist/cli/commands/adopt.performance.test.d.ts +2 -0
  19. package/dist/cli/commands/adopt.performance.test.d.ts.map +1 -0
  20. package/dist/cli/commands/adopt.performance.test.js +30 -0
  21. package/dist/cli/commands/adopt.performance.test.js.map +1 -0
  22. package/dist/cli/commands/adopt.result-shape.test.d.ts +2 -0
  23. package/dist/cli/commands/adopt.result-shape.test.d.ts.map +1 -0
  24. package/dist/cli/commands/adopt.result-shape.test.js +166 -0
  25. package/dist/cli/commands/adopt.result-shape.test.js.map +1 -0
  26. package/dist/cli/commands/adopt.serialization.test.d.ts +2 -0
  27. package/dist/cli/commands/adopt.serialization.test.d.ts.map +1 -0
  28. package/dist/cli/commands/adopt.serialization.test.js +228 -0
  29. package/dist/cli/commands/adopt.serialization.test.js.map +1 -0
  30. package/dist/cli/commands/adopt.test.js +26 -15
  31. package/dist/cli/commands/adopt.test.js.map +1 -1
  32. package/dist/cli/commands/adopt.windows-crlf.test.d.ts +2 -0
  33. package/dist/cli/commands/adopt.windows-crlf.test.d.ts.map +1 -0
  34. package/dist/cli/commands/adopt.windows-crlf.test.js +102 -0
  35. package/dist/cli/commands/adopt.windows-crlf.test.js.map +1 -0
  36. package/dist/cli/commands/init.d.ts.map +1 -1
  37. package/dist/cli/commands/init.js +4 -157
  38. package/dist/cli/commands/init.js.map +1 -1
  39. package/dist/cli/init-flag-families.d.ts +86 -0
  40. package/dist/cli/init-flag-families.d.ts.map +1 -0
  41. package/dist/cli/init-flag-families.js +418 -0
  42. package/dist/cli/init-flag-families.js.map +1 -0
  43. package/dist/cli/init-flag-families.test.d.ts +2 -0
  44. package/dist/cli/init-flag-families.test.d.ts.map +1 -0
  45. package/dist/cli/init-flag-families.test.js +268 -0
  46. package/dist/cli/init-flag-families.test.js.map +1 -0
  47. package/dist/config/schema.d.ts +6 -6
  48. package/dist/config/schema.js +2 -2
  49. package/dist/config/schema.js.map +1 -1
  50. package/dist/config/schema.test.js +10 -4
  51. package/dist/config/schema.test.js.map +1 -1
  52. package/dist/e2e/adopt-multi-type.test.d.ts +2 -0
  53. package/dist/e2e/adopt-multi-type.test.d.ts.map +1 -0
  54. package/dist/e2e/adopt-multi-type.test.js +35 -0
  55. package/dist/e2e/adopt-multi-type.test.js.map +1 -0
  56. package/dist/project/__frozen-schemas__/schema-v3.9.2.d.ts +2891 -0
  57. package/dist/project/__frozen-schemas__/schema-v3.9.2.d.ts.map +1 -0
  58. package/dist/project/__frozen-schemas__/schema-v3.9.2.js +177 -0
  59. package/dist/project/__frozen-schemas__/schema-v3.9.2.js.map +1 -0
  60. package/dist/project/adopt.d.ts +38 -2
  61. package/dist/project/adopt.d.ts.map +1 -1
  62. package/dist/project/adopt.error-messages.test.d.ts +2 -0
  63. package/dist/project/adopt.error-messages.test.d.ts.map +1 -0
  64. package/dist/project/adopt.error-messages.test.js +112 -0
  65. package/dist/project/adopt.error-messages.test.js.map +1 -0
  66. package/dist/project/adopt.forward-compat.test.d.ts +2 -0
  67. package/dist/project/adopt.forward-compat.test.d.ts.map +1 -0
  68. package/dist/project/adopt.forward-compat.test.js +71 -0
  69. package/dist/project/adopt.forward-compat.test.js.map +1 -0
  70. package/dist/project/adopt.js +218 -27
  71. package/dist/project/adopt.js.map +1 -1
  72. package/dist/project/adopt.merge.test.d.ts +2 -0
  73. package/dist/project/adopt.merge.test.d.ts.map +1 -0
  74. package/dist/project/adopt.merge.test.js +62 -0
  75. package/dist/project/adopt.merge.test.js.map +1 -0
  76. package/dist/project/adopt.re-adoption.test.d.ts +2 -0
  77. package/dist/project/adopt.re-adoption.test.d.ts.map +1 -0
  78. package/dist/project/adopt.re-adoption.test.js +222 -0
  79. package/dist/project/adopt.re-adoption.test.js.map +1 -0
  80. package/dist/project/adopt.test.js +72 -27
  81. package/dist/project/adopt.test.js.map +1 -1
  82. package/dist/project/detectors/backend.d.ts +4 -0
  83. package/dist/project/detectors/backend.d.ts.map +1 -0
  84. package/dist/project/detectors/backend.js +199 -0
  85. package/dist/project/detectors/backend.js.map +1 -0
  86. package/dist/project/detectors/backend.test.d.ts +2 -0
  87. package/dist/project/detectors/backend.test.d.ts.map +1 -0
  88. package/dist/project/detectors/backend.test.js +64 -0
  89. package/dist/project/detectors/backend.test.js.map +1 -0
  90. package/dist/project/detectors/browser-extension.d.ts +4 -0
  91. package/dist/project/detectors/browser-extension.d.ts.map +1 -0
  92. package/dist/project/detectors/browser-extension.js +61 -0
  93. package/dist/project/detectors/browser-extension.js.map +1 -0
  94. package/dist/project/detectors/browser-extension.test.d.ts +2 -0
  95. package/dist/project/detectors/browser-extension.test.d.ts.map +1 -0
  96. package/dist/project/detectors/browser-extension.test.js +64 -0
  97. package/dist/project/detectors/browser-extension.test.js.map +1 -0
  98. package/dist/project/detectors/cli.d.ts +4 -0
  99. package/dist/project/detectors/cli.d.ts.map +1 -0
  100. package/dist/project/detectors/cli.js +68 -0
  101. package/dist/project/detectors/cli.js.map +1 -0
  102. package/dist/project/detectors/cli.test.d.ts +2 -0
  103. package/dist/project/detectors/cli.test.d.ts.map +1 -0
  104. package/dist/project/detectors/cli.test.js +70 -0
  105. package/dist/project/detectors/cli.test.js.map +1 -0
  106. package/dist/project/detectors/context.d.ts +105 -0
  107. package/dist/project/detectors/context.d.ts.map +1 -0
  108. package/dist/project/detectors/context.js +652 -0
  109. package/dist/project/detectors/context.js.map +1 -0
  110. package/dist/project/detectors/context.test.d.ts +2 -0
  111. package/dist/project/detectors/context.test.d.ts.map +1 -0
  112. package/dist/project/detectors/context.test.js +240 -0
  113. package/dist/project/detectors/context.test.js.map +1 -0
  114. package/dist/project/detectors/data-pipeline.d.ts +4 -0
  115. package/dist/project/detectors/data-pipeline.d.ts.map +1 -0
  116. package/dist/project/detectors/data-pipeline.js +97 -0
  117. package/dist/project/detectors/data-pipeline.js.map +1 -0
  118. package/dist/project/detectors/data-pipeline.test.d.ts +2 -0
  119. package/dist/project/detectors/data-pipeline.test.d.ts.map +1 -0
  120. package/dist/project/detectors/data-pipeline.test.js +67 -0
  121. package/dist/project/detectors/data-pipeline.test.js.map +1 -0
  122. package/dist/project/detectors/disambiguate.d.ts +12 -0
  123. package/dist/project/detectors/disambiguate.d.ts.map +1 -0
  124. package/dist/project/detectors/disambiguate.js +87 -0
  125. package/dist/project/detectors/disambiguate.js.map +1 -0
  126. package/dist/project/detectors/disambiguate.test.d.ts +2 -0
  127. package/dist/project/detectors/disambiguate.test.d.ts.map +1 -0
  128. package/dist/project/detectors/disambiguate.test.js +114 -0
  129. package/dist/project/detectors/disambiguate.test.js.map +1 -0
  130. package/dist/project/detectors/file-text-match.d.ts +3 -0
  131. package/dist/project/detectors/file-text-match.d.ts.map +1 -0
  132. package/dist/project/detectors/file-text-match.js +60 -0
  133. package/dist/project/detectors/file-text-match.js.map +1 -0
  134. package/dist/project/detectors/file-text-match.test.d.ts +2 -0
  135. package/dist/project/detectors/file-text-match.test.d.ts.map +1 -0
  136. package/dist/project/detectors/file-text-match.test.js +81 -0
  137. package/dist/project/detectors/file-text-match.test.js.map +1 -0
  138. package/dist/project/detectors/game.d.ts +18 -0
  139. package/dist/project/detectors/game.d.ts.map +1 -0
  140. package/dist/project/detectors/game.js +83 -0
  141. package/dist/project/detectors/game.js.map +1 -0
  142. package/dist/project/detectors/game.test.d.ts +2 -0
  143. package/dist/project/detectors/game.test.d.ts.map +1 -0
  144. package/dist/project/detectors/game.test.js +87 -0
  145. package/dist/project/detectors/game.test.js.map +1 -0
  146. package/dist/project/detectors/index.d.ts +5 -0
  147. package/dist/project/detectors/index.d.ts.map +1 -0
  148. package/dist/project/detectors/index.js +29 -0
  149. package/dist/project/detectors/index.js.map +1 -0
  150. package/dist/project/detectors/library.d.ts +4 -0
  151. package/dist/project/detectors/library.d.ts.map +1 -0
  152. package/dist/project/detectors/library.js +122 -0
  153. package/dist/project/detectors/library.js.map +1 -0
  154. package/dist/project/detectors/library.test.d.ts +2 -0
  155. package/dist/project/detectors/library.test.d.ts.map +1 -0
  156. package/dist/project/detectors/library.test.js +95 -0
  157. package/dist/project/detectors/library.test.js.map +1 -0
  158. package/dist/project/detectors/ml.d.ts +4 -0
  159. package/dist/project/detectors/ml.d.ts.map +1 -0
  160. package/dist/project/detectors/ml.js +112 -0
  161. package/dist/project/detectors/ml.js.map +1 -0
  162. package/dist/project/detectors/ml.test.d.ts +2 -0
  163. package/dist/project/detectors/ml.test.d.ts.map +1 -0
  164. package/dist/project/detectors/ml.test.js +75 -0
  165. package/dist/project/detectors/ml.test.js.map +1 -0
  166. package/dist/project/detectors/mobile-app.d.ts +4 -0
  167. package/dist/project/detectors/mobile-app.d.ts.map +1 -0
  168. package/dist/project/detectors/mobile-app.js +58 -0
  169. package/dist/project/detectors/mobile-app.js.map +1 -0
  170. package/dist/project/detectors/mobile-app.test.d.ts +2 -0
  171. package/dist/project/detectors/mobile-app.test.d.ts.map +1 -0
  172. package/dist/project/detectors/mobile-app.test.js +57 -0
  173. package/dist/project/detectors/mobile-app.test.js.map +1 -0
  174. package/dist/project/detectors/required-fields.d.ts +4 -0
  175. package/dist/project/detectors/required-fields.d.ts.map +1 -0
  176. package/dist/project/detectors/required-fields.js +13 -0
  177. package/dist/project/detectors/required-fields.js.map +1 -0
  178. package/dist/project/detectors/required-fields.test.d.ts +2 -0
  179. package/dist/project/detectors/required-fields.test.d.ts.map +1 -0
  180. package/dist/project/detectors/required-fields.test.js +24 -0
  181. package/dist/project/detectors/required-fields.test.js.map +1 -0
  182. package/dist/project/detectors/resolve-detection.d.ts +18 -0
  183. package/dist/project/detectors/resolve-detection.d.ts.map +1 -0
  184. package/dist/project/detectors/resolve-detection.js +184 -0
  185. package/dist/project/detectors/resolve-detection.js.map +1 -0
  186. package/dist/project/detectors/resolve-detection.test.d.ts +2 -0
  187. package/dist/project/detectors/resolve-detection.test.d.ts.map +1 -0
  188. package/dist/project/detectors/resolve-detection.test.js +158 -0
  189. package/dist/project/detectors/resolve-detection.test.js.map +1 -0
  190. package/dist/project/detectors/types.d.ts +56 -0
  191. package/dist/project/detectors/types.d.ts.map +1 -0
  192. package/dist/project/detectors/types.js +9 -0
  193. package/dist/project/detectors/types.js.map +1 -0
  194. package/dist/project/detectors/web-app.d.ts +15 -0
  195. package/dist/project/detectors/web-app.d.ts.map +1 -0
  196. package/dist/project/detectors/web-app.js +228 -0
  197. package/dist/project/detectors/web-app.js.map +1 -0
  198. package/dist/project/detectors/web-app.test.d.ts +2 -0
  199. package/dist/project/detectors/web-app.test.d.ts.map +1 -0
  200. package/dist/project/detectors/web-app.test.js +95 -0
  201. package/dist/project/detectors/web-app.test.js.map +1 -0
  202. package/dist/types/config.d.ts +33 -0
  203. package/dist/types/config.d.ts.map +1 -1
  204. package/dist/types/enums.d.ts +2 -1
  205. package/dist/types/enums.d.ts.map +1 -1
  206. package/dist/types/enums.js +1 -0
  207. package/dist/types/enums.js.map +1 -1
  208. package/dist/utils/errors.d.ts +7 -0
  209. package/dist/utils/errors.d.ts.map +1 -1
  210. package/dist/utils/errors.js +38 -0
  211. package/dist/utils/errors.js.map +1 -1
  212. package/dist/utils/errors.test.js +42 -1
  213. package/dist/utils/errors.test.js.map +1 -1
  214. package/package.json +6 -2
package/README.md CHANGED
@@ -673,17 +673,48 @@ These answers control which conditional steps activate. A single-player puzzle g
673
673
  | `live-ops-plan` | Live-ops selected | Content cadence, events, hotfix deployment, maintenance |
674
674
  | `platform-cert-prep` | Console/mobile/VR targets | Sony TRC, Xbox XR, Nintendo Lotcheck, store compliance checklists |
675
675
 
676
- #### Engine Detection
676
+ #### Multi-type Detection
677
677
 
678
- `scaffold adopt` automatically detects game engines in existing projects:
678
+ `scaffold adopt` detects 9 project types from manifest files and directory layouts:
679
679
 
680
- | Engine | Detection Signal |
681
- |--------|-----------------|
682
- | Unity | `Assets/*.meta` files |
683
- | Unreal | `*.uproject` file |
684
- | Godot | `project.godot` file |
680
+ | Type | Key Signals |
681
+ |------|-------------|
682
+ | `web-app` | `next.config.*`, `nuxt.config.*`, `app/` router dirs, SPA frameworks |
683
+ | `backend` | `routes/` or `controllers/`, ORM schemas, server deps |
684
+ | `cli` | `bin` field in manifest, `commander`/`yargs`/`clap` deps |
685
+ | `library` | `main`/`types` fields, peer dependencies, no `bin` |
686
+ | `mobile-app` | `app.json` (Expo), `ios/`/`android/` dirs, React Native deps |
687
+ | `game` | `Assets/*.meta` (Unity), `*.uproject` (Unreal), `project.godot` (Godot) |
688
+ | `data-pipeline` | `dags/` dir, Airflow/Prefect/Dagster deps, Spark configs |
689
+ | `ml` | `training/`/`models/` dirs, PyTorch/TensorFlow deps, MLflow configs |
690
+ | `browser-extension` | `manifest.json` with `manifest_version` field |
691
+
692
+ Each detector returns a confidence tier (high/medium/low) with evidence trails. Override detection with `--project-type <type>`.
693
+
694
+ #### Multi-type Disambiguation
695
+
696
+ When `scaffold adopt` finds signals matching multiple project types, you'll
697
+ see a radio prompt:
698
+
699
+ ```
700
+ ? Which best describes this project? (Use arrow keys)
701
+ > web-app [high] next-config (next.config.mjs), app-router-dir (app/page.tsx), public-dir (public/), react-dep
702
+ backend [high] routes-dir (app/api), prisma-schema (prisma/schema.prisma), pg-dep
703
+ library [medium] pkg-main-field (package.json), pkg-types-field (package.json), peer-deps (react)
704
+ None of these — continue without a project type
705
+ ```
706
+
707
+ The default selection is the highest-confidence match with the most evidence. Press Enter to accept, or use arrow keys to pick a different option.
708
+
709
+ For non-interactive use (CI, scripts), pass `--project-type <type>` explicitly:
710
+
711
+ ```bash
712
+ scaffold adopt --auto --project-type web-app
713
+ ```
685
714
 
686
- When detected, `scaffold adopt` sets `projectType: game` and `gameConfig.engine` in your config, enabling the full game overlay.
715
+ If you run `scaffold adopt --auto` and detection is ambiguous, the command
716
+ exits with code 6 (`ExitCode.Ambiguous`) and lists the candidate types in the
717
+ error message.
687
718
 
688
719
  ## The Pipeline
689
720
 
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=adopt.cli-flags.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adopt.cli-flags.test.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/adopt.cli-flags.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,165 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ // ---------------------------------------------------------------------------
6
+ // Hoisted mocks — needed because runAdoption calls detectProjectMode and
7
+ // discoverMetaPrompts. We mock at the paths that adopt.ts imports from.
8
+ // ---------------------------------------------------------------------------
9
+ vi.mock('../../project/detector.js', () => ({
10
+ detectProjectMode: vi.fn(() => ({
11
+ mode: 'brownfield',
12
+ signals: [],
13
+ methodologySuggestion: 'deep',
14
+ sourceFileCount: 10,
15
+ })),
16
+ }));
17
+ vi.mock('../../core/assembly/meta-prompt-loader.js', () => ({
18
+ discoverMetaPrompts: vi.fn(() => new Map()),
19
+ }));
20
+ // ---------------------------------------------------------------------------
21
+ // Imports (after mocks)
22
+ // ---------------------------------------------------------------------------
23
+ import { runAdoption } from '../../project/adopt.js';
24
+ import { buildFlagOverrides, applyFlagFamilyValidation } from '../init-flag-families.js';
25
+ // ---------------------------------------------------------------------------
26
+ // Helpers
27
+ // ---------------------------------------------------------------------------
28
+ function makeTmpProject(files) {
29
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'adopt-flags-'));
30
+ for (const [rel, content] of Object.entries(files)) {
31
+ const full = path.join(dir, rel);
32
+ fs.mkdirSync(path.dirname(full), { recursive: true });
33
+ fs.writeFileSync(full, content);
34
+ }
35
+ return dir;
36
+ }
37
+ // ---------------------------------------------------------------------------
38
+ // Tests
39
+ // ---------------------------------------------------------------------------
40
+ describe('adopt CLI flag integration', () => {
41
+ let tmpDirs;
42
+ beforeEach(() => {
43
+ tmpDirs = [];
44
+ });
45
+ afterEach(() => {
46
+ for (const d of tmpDirs) {
47
+ fs.rmSync(d, { recursive: true, force: true });
48
+ }
49
+ });
50
+ function tracked(dir) {
51
+ tmpDirs.push(dir);
52
+ return dir;
53
+ }
54
+ // -------------------------------------------------------------------------
55
+ // buildFlagOverrides unit-level integration
56
+ // -------------------------------------------------------------------------
57
+ it('buildFlagOverrides returns undefined when no family flags present', () => {
58
+ expect(buildFlagOverrides({})).toBeUndefined();
59
+ });
60
+ it('--backend-api-style graphql produces correct override shape', () => {
61
+ const overrides = buildFlagOverrides({ 'backend-api-style': 'graphql' });
62
+ expect(overrides?.type).toBe('backend');
63
+ expect(overrides?.partial).toEqual(expect.objectContaining({ apiStyle: 'graphql' }));
64
+ });
65
+ it('--web-rendering ssr produces web-app override with renderingStrategy', () => {
66
+ const overrides = buildFlagOverrides({ 'web-rendering': 'ssr' });
67
+ expect(overrides?.type).toBe('web-app');
68
+ expect(overrides?.partial).toEqual(expect.objectContaining({ renderingStrategy: 'ssr' }));
69
+ });
70
+ it('--engine unity produces game override with engine', () => {
71
+ const overrides = buildFlagOverrides({ engine: 'unity' });
72
+ expect(overrides?.type).toBe('game');
73
+ expect(overrides?.partial).toEqual(expect.objectContaining({ engine: 'unity' }));
74
+ });
75
+ it('--ml-phase training produces ml override with projectPhase', () => {
76
+ const overrides = buildFlagOverrides({ 'ml-phase': 'training' });
77
+ expect(overrides?.type).toBe('ml');
78
+ expect(overrides?.partial).toEqual(expect.objectContaining({ projectPhase: 'training' }));
79
+ });
80
+ it('--mobile-platform ios produces mobile-app override', () => {
81
+ const overrides = buildFlagOverrides({ 'mobile-platform': 'ios' });
82
+ expect(overrides?.type).toBe('mobile-app');
83
+ expect(overrides?.partial).toEqual(expect.objectContaining({ platform: 'ios' }));
84
+ });
85
+ it('--ext-manifest 3 produces browser-extension override', () => {
86
+ const overrides = buildFlagOverrides({ 'ext-manifest': '3' });
87
+ expect(overrides?.type).toBe('browser-extension');
88
+ expect(overrides?.partial).toEqual(expect.objectContaining({ manifestVersion: '3' }));
89
+ });
90
+ it('--pipeline-processing streaming produces data-pipeline override', () => {
91
+ const overrides = buildFlagOverrides({ 'pipeline-processing': 'streaming' });
92
+ expect(overrides?.type).toBe('data-pipeline');
93
+ expect(overrides?.partial).toEqual(expect.objectContaining({ processingModel: 'streaming' }));
94
+ });
95
+ it('--lib-visibility public produces library override', () => {
96
+ const overrides = buildFlagOverrides({ 'lib-visibility': 'public' });
97
+ expect(overrides?.type).toBe('library');
98
+ expect(overrides?.partial).toEqual(expect.objectContaining({ visibility: 'public' }));
99
+ });
100
+ it('--cli-interactivity hybrid produces cli override', () => {
101
+ const overrides = buildFlagOverrides({ 'cli-interactivity': 'hybrid' });
102
+ expect(overrides?.type).toBe('cli');
103
+ expect(overrides?.partial).toEqual(expect.objectContaining({ interactivity: 'hybrid' }));
104
+ });
105
+ // -------------------------------------------------------------------------
106
+ // Validation — mixed families and project-type mismatches
107
+ // -------------------------------------------------------------------------
108
+ it('mixed family flags throw during validation', () => {
109
+ const argv = { 'web-rendering': 'ssr', 'backend-api-style': 'rest' };
110
+ expect(() => applyFlagFamilyValidation(argv)).toThrow(/Cannot mix flags/);
111
+ });
112
+ it('--web-rendering with --project-type backend throws', () => {
113
+ const argv = { 'project-type': 'backend', 'web-rendering': 'ssr' };
114
+ expect(() => applyFlagFamilyValidation(argv)).toThrow(/--web-\* flags require --project-type web-app/);
115
+ });
116
+ it('--backend-api-style with --project-type web-app throws', () => {
117
+ const argv = { 'project-type': 'web-app', 'backend-api-style': 'rest' };
118
+ expect(() => applyFlagFamilyValidation(argv)).toThrow(/--backend-\* flags require --project-type backend/);
119
+ });
120
+ it('game flags with --project-type cli throws', () => {
121
+ const argv = { 'project-type': 'cli', engine: 'unity' };
122
+ expect(() => applyFlagFamilyValidation(argv)).toThrow(/Game flags .* require --project-type game/);
123
+ });
124
+ // -------------------------------------------------------------------------
125
+ // Flag overrides flow through runAdoption
126
+ // -------------------------------------------------------------------------
127
+ it('--engine unity override flows through to runAdoption result', async () => {
128
+ const dir = tracked(makeTmpProject({
129
+ 'Assets/foo.meta': '',
130
+ }));
131
+ const overrides = buildFlagOverrides({ engine: 'godot' });
132
+ const result = await runAdoption({
133
+ projectRoot: dir,
134
+ metaPromptDir: path.join(dir, '.scaffold'),
135
+ methodology: 'deep',
136
+ dryRun: true,
137
+ auto: true,
138
+ force: true,
139
+ verbose: false,
140
+ explicitProjectType: 'game',
141
+ flagOverrides: overrides,
142
+ });
143
+ // Detection finds unity (Assets/.meta) but flag override says godot
144
+ expect(result.projectType).toBe('game');
145
+ expect(result.detectedConfig?.config?.engine).toBe('godot');
146
+ });
147
+ it('--backend-api-style graphql with --project-type backend sets apiStyle', async () => {
148
+ const dir = tracked(makeTmpProject({}));
149
+ const overrides = buildFlagOverrides({ 'backend-api-style': 'graphql' });
150
+ const result = await runAdoption({
151
+ projectRoot: dir,
152
+ metaPromptDir: path.join(dir, '.scaffold'),
153
+ methodology: 'deep',
154
+ dryRun: true,
155
+ auto: true,
156
+ force: true,
157
+ verbose: false,
158
+ explicitProjectType: 'backend',
159
+ flagOverrides: overrides,
160
+ });
161
+ expect(result.projectType).toBe('backend');
162
+ expect(result.detectedConfig?.config?.apiStyle).toBe('graphql');
163
+ });
164
+ });
165
+ //# sourceMappingURL=adopt.cli-flags.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adopt.cli-flags.test.js","sourceRoot":"","sources":["../../../src/cli/commands/adopt.cli-flags.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=adopt.config-resolution.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adopt.config-resolution.test.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/adopt.config-resolution.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,217 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ // ---------------------------------------------------------------------------
6
+ // Hoisted mocks
7
+ // ---------------------------------------------------------------------------
8
+ vi.mock('../../project/detector.js', () => ({
9
+ detectProjectMode: vi.fn(() => ({
10
+ mode: 'brownfield',
11
+ signals: [],
12
+ methodologySuggestion: 'deep',
13
+ sourceFileCount: 10,
14
+ })),
15
+ }));
16
+ vi.mock('../../core/assembly/meta-prompt-loader.js', () => ({
17
+ discoverMetaPrompts: vi.fn(() => new Map()),
18
+ }));
19
+ // ---------------------------------------------------------------------------
20
+ // Imports (after mocks)
21
+ // ---------------------------------------------------------------------------
22
+ import { runAdoption } from '../../project/adopt.js';
23
+ // ---------------------------------------------------------------------------
24
+ // Helpers
25
+ // ---------------------------------------------------------------------------
26
+ function makeTmpProject(files) {
27
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'adopt-write-'));
28
+ for (const [rel, content] of Object.entries(files)) {
29
+ const full = path.join(dir, rel);
30
+ fs.mkdirSync(path.dirname(full), { recursive: true });
31
+ fs.writeFileSync(full, content);
32
+ }
33
+ return dir;
34
+ }
35
+ // ---------------------------------------------------------------------------
36
+ // Tests
37
+ // ---------------------------------------------------------------------------
38
+ describe('adopt config write', () => {
39
+ let tmpDirs;
40
+ beforeEach(() => {
41
+ tmpDirs = [];
42
+ });
43
+ afterEach(() => {
44
+ for (const d of tmpDirs) {
45
+ fs.rmSync(d, { recursive: true, force: true });
46
+ }
47
+ });
48
+ function tracked(dir) {
49
+ tmpDirs.push(dir);
50
+ return dir;
51
+ }
52
+ it('dry-run produces detectedConfig without writing files', async () => {
53
+ const dir = tracked(makeTmpProject({
54
+ 'Assets/foo.meta': '',
55
+ }));
56
+ const result = await runAdoption({
57
+ projectRoot: dir,
58
+ metaPromptDir: path.join(dir, '.scaffold'),
59
+ methodology: 'deep',
60
+ dryRun: true,
61
+ auto: true,
62
+ force: true,
63
+ verbose: false,
64
+ });
65
+ expect(result.detectedConfig?.type).toBe('game');
66
+ // No .scaffold/config.yml created in dry-run (runAdoption doesn't write files)
67
+ expect(fs.existsSync(path.join(dir, '.scaffold', 'config.yml'))).toBe(false);
68
+ });
69
+ it('merge preserves existing config values over detection', async () => {
70
+ const dir = tracked(makeTmpProject({
71
+ 'Assets/foo.meta': '',
72
+ '.scaffold/config.yml': 'version: 2\nproject:\n projectType: game\n gameConfig:\n engine: unreal\n',
73
+ }));
74
+ const result = await runAdoption({
75
+ projectRoot: dir,
76
+ metaPromptDir: path.join(dir, '.scaffold'),
77
+ methodology: 'deep',
78
+ dryRun: true,
79
+ auto: true,
80
+ force: true,
81
+ verbose: false,
82
+ });
83
+ // Detection finds unity (Assets/.meta), but existing says unreal
84
+ // Existing wins per merge pipeline invariant
85
+ const config = result.detectedConfig?.config;
86
+ expect(config?.engine).toBe('unreal');
87
+ // Should emit field conflict warning
88
+ expect(result.warnings.some(w => w.code === 'ADOPT_FIELD_CONFLICT')).toBe(true);
89
+ });
90
+ it('existing config with bare project: (null scalar) does not crash', async () => {
91
+ const dir = tracked(makeTmpProject({
92
+ 'Assets/foo.meta': '',
93
+ '.scaffold/config.yml': 'version: 2\nproject:\n',
94
+ }));
95
+ const result = await runAdoption({
96
+ projectRoot: dir,
97
+ metaPromptDir: path.join(dir, '.scaffold'),
98
+ methodology: 'deep',
99
+ dryRun: true,
100
+ auto: true,
101
+ force: true,
102
+ verbose: false,
103
+ });
104
+ expect(result.errors).toHaveLength(0);
105
+ expect(result.detectedConfig?.type).toBe('game');
106
+ });
107
+ it('malformed YAML config produces an error', async () => {
108
+ const dir = tracked(makeTmpProject({
109
+ 'Assets/foo.meta': '',
110
+ '.scaffold/config.yml': '{unclosed',
111
+ }));
112
+ const result = await runAdoption({
113
+ projectRoot: dir,
114
+ metaPromptDir: path.join(dir, '.scaffold'),
115
+ methodology: 'deep',
116
+ dryRun: true,
117
+ auto: true,
118
+ force: true,
119
+ verbose: false,
120
+ });
121
+ expect(result.errors.length).toBeGreaterThan(0);
122
+ expect(result.errors[0].code).toBe('CONFIG_PARSE_ERROR');
123
+ });
124
+ it('type conflict without --force returns error', async () => {
125
+ const dir = tracked(makeTmpProject({
126
+ 'Assets/foo.meta': '',
127
+ '.scaffold/config.yml': 'version: 2\nproject:\n projectType: game\n gameConfig:\n engine: unity\n',
128
+ }));
129
+ const result = await runAdoption({
130
+ projectRoot: dir,
131
+ metaPromptDir: path.join(dir, '.scaffold'),
132
+ methodology: 'deep',
133
+ dryRun: true,
134
+ auto: true,
135
+ force: false,
136
+ verbose: false,
137
+ explicitProjectType: 'web-app',
138
+ });
139
+ expect(result.errors.some(e => e.code === 'ADOPT_TYPE_CONFLICT')).toBe(true);
140
+ });
141
+ it('preserves YAML comments in existing config without crashing', async () => {
142
+ const dir = tracked(makeTmpProject({
143
+ 'Assets/foo.meta': '',
144
+ '.scaffold/config.yml': '# My config comment\nversion: 2\nproject:\n projectType: game\n'
145
+ + ' gameConfig:\n engine: unity\n',
146
+ }));
147
+ const result = await runAdoption({
148
+ projectRoot: dir,
149
+ metaPromptDir: path.join(dir, '.scaffold'),
150
+ methodology: 'deep',
151
+ dryRun: true,
152
+ auto: true,
153
+ force: true,
154
+ verbose: false,
155
+ });
156
+ expect(result.errors).toHaveLength(0);
157
+ expect(result.projectType).toBe('game');
158
+ });
159
+ it('re-adoption without --force skips detection and returns ADOPT_DETECTION_INCONCLUSIVE', async () => {
160
+ const dir = tracked(makeTmpProject({
161
+ 'Assets/foo.meta': '',
162
+ '.scaffold/config.yml': 'version: 2\nproject:\n projectType: game\n',
163
+ }));
164
+ const result = await runAdoption({
165
+ projectRoot: dir,
166
+ metaPromptDir: path.join(dir, '.scaffold'),
167
+ methodology: 'deep',
168
+ dryRun: true,
169
+ auto: true,
170
+ force: false,
171
+ verbose: false,
172
+ });
173
+ expect(result.projectType).toBe('game');
174
+ expect(result.detectedConfig).toBeUndefined();
175
+ expect(result.warnings.some(w => w.code === 'ADOPT_DETECTION_INCONCLUSIVE')).toBe(true);
176
+ });
177
+ it('type conflict with --force allows type change and emits ADOPT_TYPE_CHANGED', async () => {
178
+ const dir = tracked(makeTmpProject({
179
+ 'Assets/foo.meta': '',
180
+ '.scaffold/config.yml': 'version: 2\nproject:\n projectType: backend\n backendConfig:\n apiStyle: rest\n',
181
+ }));
182
+ const result = await runAdoption({
183
+ projectRoot: dir,
184
+ metaPromptDir: path.join(dir, '.scaffold'),
185
+ methodology: 'deep',
186
+ dryRun: true,
187
+ auto: true,
188
+ force: true,
189
+ verbose: false,
190
+ });
191
+ // Assets/.meta → detection wins with game
192
+ expect(result.projectType).toBe('game');
193
+ expect(result.errors).toHaveLength(0);
194
+ expect(result.warnings.some(w => w.code === 'ADOPT_TYPE_CHANGED')).toBe(true);
195
+ });
196
+ it('explicit --project-type with matching existing config runs detection', async () => {
197
+ const dir = tracked(makeTmpProject({
198
+ 'Assets/foo.meta': '',
199
+ '.scaffold/config.yml': 'version: 2\nproject:\n projectType: game\n gameConfig:\n engine: unity\n',
200
+ }));
201
+ const result = await runAdoption({
202
+ projectRoot: dir,
203
+ metaPromptDir: path.join(dir, '.scaffold'),
204
+ methodology: 'deep',
205
+ dryRun: true,
206
+ auto: true,
207
+ force: false,
208
+ verbose: false,
209
+ explicitProjectType: 'game',
210
+ });
211
+ // Detection ran because explicit type bypasses re-adoption gating
212
+ expect(result.projectType).toBe('game');
213
+ expect(result.detectedConfig).toBeDefined();
214
+ expect(result.errors).toHaveLength(0);
215
+ });
216
+ });
217
+ //# sourceMappingURL=adopt.config-resolution.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adopt.config-resolution.test.js","sourceRoot":"","sources":["../../../src/cli/commands/adopt.config-resolution.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=adopt.config-write-integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adopt.config-write-integration.test.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/adopt.config-write-integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,138 @@
1
+ import { describe, it, expect, afterEach } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { writeOrUpdateConfig } from './adopt.js';
6
+ function makeTmpDir() {
7
+ return fs.mkdtempSync(path.join(os.tmpdir(), 'adopt-write-int-'));
8
+ }
9
+ function makeResult(overrides = {}) {
10
+ return {
11
+ mode: 'brownfield',
12
+ artifactsFound: 0,
13
+ detectedArtifacts: [],
14
+ stepsCompleted: [],
15
+ stepsRemaining: [],
16
+ methodology: 'deep',
17
+ errors: [],
18
+ warnings: [],
19
+ ...overrides,
20
+ };
21
+ }
22
+ describe('writeOrUpdateConfig integration', () => {
23
+ const tmpDirs = [];
24
+ afterEach(() => {
25
+ for (const d of tmpDirs)
26
+ fs.rmSync(d, { recursive: true, force: true });
27
+ tmpDirs.length = 0;
28
+ });
29
+ function tracked(dir) {
30
+ tmpDirs.push(dir);
31
+ return dir;
32
+ }
33
+ it('bootstraps new config.yml when none exists', () => {
34
+ const dir = tracked(makeTmpDir());
35
+ const result = makeResult({
36
+ projectType: 'web-app',
37
+ detectedConfig: {
38
+ type: 'web-app',
39
+ config: { renderingStrategy: 'ssr' },
40
+ },
41
+ });
42
+ writeOrUpdateConfig(dir, result);
43
+ const content = fs.readFileSync(path.join(dir, '.scaffold', 'config.yml'), 'utf8');
44
+ expect(content).toContain('projectType: web-app');
45
+ expect(content).toContain('renderingStrategy: ssr');
46
+ expect(content).toContain('version: 2');
47
+ });
48
+ it('preserves comments in existing config.yml', () => {
49
+ const dir = tracked(makeTmpDir());
50
+ fs.mkdirSync(path.join(dir, '.scaffold'), { recursive: true });
51
+ fs.writeFileSync(path.join(dir, '.scaffold', 'config.yml'), '# My custom comment\nversion: 2\nproject:\n projectType: web-app\n');
52
+ const result = makeResult({
53
+ projectType: 'web-app',
54
+ detectedConfig: {
55
+ type: 'web-app',
56
+ config: { renderingStrategy: 'ssr' },
57
+ },
58
+ });
59
+ writeOrUpdateConfig(dir, result);
60
+ const content = fs.readFileSync(path.join(dir, '.scaffold', 'config.yml'), 'utf8');
61
+ expect(content).toContain('# My custom comment');
62
+ expect(content).toContain('renderingStrategy: ssr');
63
+ });
64
+ it('removes stale config blocks when switching project types', () => {
65
+ const dir = tracked(makeTmpDir());
66
+ fs.mkdirSync(path.join(dir, '.scaffold'), { recursive: true });
67
+ fs.writeFileSync(path.join(dir, '.scaffold', 'config.yml'), 'version: 2\nproject:\n projectType: game\n gameConfig:\n engine: unity\n');
68
+ const result = makeResult({
69
+ projectType: 'web-app',
70
+ detectedConfig: {
71
+ type: 'web-app',
72
+ config: { renderingStrategy: 'ssr' },
73
+ },
74
+ });
75
+ writeOrUpdateConfig(dir, result);
76
+ const content = fs.readFileSync(path.join(dir, '.scaffold', 'config.yml'), 'utf8');
77
+ expect(content).toContain('projectType: web-app');
78
+ expect(content).toContain('webAppConfig');
79
+ expect(content).not.toContain('gameConfig');
80
+ expect(content).not.toContain('engine: unity');
81
+ });
82
+ it('handles bare project: (null scalar) without crashing', () => {
83
+ const dir = tracked(makeTmpDir());
84
+ fs.mkdirSync(path.join(dir, '.scaffold'), { recursive: true });
85
+ fs.writeFileSync(path.join(dir, '.scaffold', 'config.yml'), 'version: 2\nproject:\n');
86
+ const result = makeResult({
87
+ projectType: 'backend',
88
+ detectedConfig: {
89
+ type: 'backend',
90
+ config: { apiStyle: 'rest' },
91
+ },
92
+ });
93
+ expect(() => writeOrUpdateConfig(dir, result)).not.toThrow();
94
+ const content = fs.readFileSync(path.join(dir, '.scaffold', 'config.yml'), 'utf8');
95
+ expect(content).toContain('projectType: backend');
96
+ expect(content).toContain('backendConfig');
97
+ });
98
+ it('throws on malformed YAML', () => {
99
+ const dir = tracked(makeTmpDir());
100
+ fs.mkdirSync(path.join(dir, '.scaffold'), { recursive: true });
101
+ fs.writeFileSync(path.join(dir, '.scaffold', 'config.yml'), '{{{{invalid!');
102
+ const result = makeResult({
103
+ projectType: 'web-app',
104
+ detectedConfig: {
105
+ type: 'web-app',
106
+ config: { renderingStrategy: 'ssr' },
107
+ },
108
+ });
109
+ expect(() => writeOrUpdateConfig(dir, result)).toThrow();
110
+ });
111
+ it('uses atomic tmp+rename write (no partial writes)', () => {
112
+ const dir = tracked(makeTmpDir());
113
+ const result = makeResult({
114
+ projectType: 'cli',
115
+ detectedConfig: {
116
+ type: 'cli',
117
+ config: { interactivity: 'args-only' },
118
+ },
119
+ });
120
+ writeOrUpdateConfig(dir, result);
121
+ const configPath = path.join(dir, '.scaffold', 'config.yml');
122
+ expect(fs.existsSync(configPath)).toBe(true);
123
+ // No tmp file left behind
124
+ const tmpPath = `${configPath}.${process.pid}.tmp`;
125
+ expect(fs.existsSync(tmpPath)).toBe(false);
126
+ });
127
+ it('does nothing when result has no projectType', () => {
128
+ const dir = tracked(makeTmpDir());
129
+ fs.mkdirSync(path.join(dir, '.scaffold'), { recursive: true });
130
+ fs.writeFileSync(path.join(dir, '.scaffold', 'config.yml'), 'version: 2\nproject:\n');
131
+ const result = makeResult(); // no projectType, no detectedConfig
132
+ writeOrUpdateConfig(dir, result);
133
+ const content = fs.readFileSync(path.join(dir, '.scaffold', 'config.yml'), 'utf8');
134
+ // File should be unchanged (no projectType mutation)
135
+ expect(content).not.toContain('projectType:');
136
+ });
137
+ });
138
+ //# sourceMappingURL=adopt.config-write-integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adopt.config-write-integration.test.js","sourceRoot":"","sources":["../../../src/cli/commands/adopt.config-write-integration.test.ts"],"names":[],"mappings":"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"}