container-superposition 0.1.7 → 0.1.9

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 (242) hide show
  1. package/README.md +24 -15
  2. package/dist/scripts/init.js +1 -1537
  3. package/dist/scripts/init.js.map +1 -1
  4. package/dist/tool/cli/args.d.ts +20 -0
  5. package/dist/tool/cli/args.d.ts.map +1 -0
  6. package/dist/tool/cli/args.js +325 -0
  7. package/dist/tool/cli/args.js.map +1 -0
  8. package/dist/tool/cli/run.d.ts +2 -0
  9. package/dist/tool/cli/run.d.ts.map +1 -0
  10. package/dist/tool/cli/run.js +318 -0
  11. package/dist/tool/cli/run.js.map +1 -0
  12. package/dist/tool/commands/adopt.js +1 -1
  13. package/dist/tool/commands/adopt.js.map +1 -1
  14. package/dist/tool/commands/doctor.d.ts +1 -0
  15. package/dist/tool/commands/doctor.d.ts.map +1 -1
  16. package/dist/tool/commands/doctor.js +1510 -78
  17. package/dist/tool/commands/doctor.js.map +1 -1
  18. package/dist/tool/commands/explain.d.ts.map +1 -1
  19. package/dist/tool/commands/explain.js +9 -0
  20. package/dist/tool/commands/explain.js.map +1 -1
  21. package/dist/tool/commands/migrate.d.ts +7 -0
  22. package/dist/tool/commands/migrate.d.ts.map +1 -0
  23. package/dist/tool/commands/migrate.js +52 -0
  24. package/dist/tool/commands/migrate.js.map +1 -0
  25. package/dist/tool/questionnaire/answers.d.ts +16 -0
  26. package/dist/tool/questionnaire/answers.d.ts.map +1 -0
  27. package/dist/tool/questionnaire/answers.js +102 -0
  28. package/dist/tool/questionnaire/answers.js.map +1 -0
  29. package/dist/tool/questionnaire/composer.d.ts +6 -4
  30. package/dist/tool/questionnaire/composer.d.ts.map +1 -1
  31. package/dist/tool/questionnaire/composer.js +778 -45
  32. package/dist/tool/questionnaire/composer.js.map +1 -1
  33. package/dist/tool/questionnaire/presets.d.ts +60 -0
  34. package/dist/tool/questionnaire/presets.d.ts.map +1 -0
  35. package/dist/tool/questionnaire/presets.js +165 -0
  36. package/dist/tool/questionnaire/presets.js.map +1 -0
  37. package/dist/tool/questionnaire/questionnaire.d.ts +10 -0
  38. package/dist/tool/questionnaire/questionnaire.d.ts.map +1 -0
  39. package/dist/tool/questionnaire/questionnaire.js +582 -0
  40. package/dist/tool/questionnaire/questionnaire.js.map +1 -0
  41. package/dist/tool/schema/manifest-migrations.d.ts +5 -0
  42. package/dist/tool/schema/manifest-migrations.d.ts.map +1 -1
  43. package/dist/tool/schema/manifest-migrations.js +45 -0
  44. package/dist/tool/schema/manifest-migrations.js.map +1 -1
  45. package/dist/tool/schema/overlay-loader.d.ts.map +1 -1
  46. package/dist/tool/schema/overlay-loader.js +24 -0
  47. package/dist/tool/schema/overlay-loader.js.map +1 -1
  48. package/dist/tool/schema/project-config.d.ts +13 -1
  49. package/dist/tool/schema/project-config.d.ts.map +1 -1
  50. package/dist/tool/schema/project-config.js +188 -10
  51. package/dist/tool/schema/project-config.js.map +1 -1
  52. package/dist/tool/schema/target-rules.d.ts +78 -0
  53. package/dist/tool/schema/target-rules.d.ts.map +1 -0
  54. package/dist/tool/schema/target-rules.js +367 -0
  55. package/dist/tool/schema/target-rules.js.map +1 -0
  56. package/dist/tool/schema/types.d.ts +42 -3
  57. package/dist/tool/schema/types.d.ts.map +1 -1
  58. package/dist/tool/utils/parameters.d.ts +76 -0
  59. package/dist/tool/utils/parameters.d.ts.map +1 -0
  60. package/dist/tool/utils/parameters.js +125 -0
  61. package/dist/tool/utils/parameters.js.map +1 -0
  62. package/dist/tool/utils/paths.d.ts +2 -0
  63. package/dist/tool/utils/paths.d.ts.map +1 -0
  64. package/dist/tool/utils/paths.js +31 -0
  65. package/dist/tool/utils/paths.js.map +1 -0
  66. package/docs/deployment-targets.md +88 -56
  67. package/docs/examples.md +20 -17
  68. package/docs/filesystem-contract.md +5 -0
  69. package/docs/minimal-and-editor.md +65 -5
  70. package/docs/overlay-imports.md +92 -14
  71. package/docs/overlays.md +231 -135
  72. package/docs/specs/001-verbose-plan-graph/spec.md +5 -12
  73. package/docs/specs/002-superposition-config-file/spec.md +5 -12
  74. package/docs/specs/003-mkdocs2-overlay/spec.md +2 -9
  75. package/docs/specs/004-doctor-fix/spec.md +1 -8
  76. package/docs/specs/005-cuda-overlay/spec.md +2 -9
  77. package/docs/specs/006-rocm-overlay/spec.md +3 -10
  78. package/docs/specs/007-target-aware-generation/spec.md +119 -0
  79. package/docs/specs/008-project-file-canonical/spec.md +82 -0
  80. package/docs/specs/009-project-env/spec.md +140 -0
  81. package/docs/specs/010-compose-env-materialization/spec.md +123 -0
  82. package/docs/specs/011-overlay-parameters/spec.md +228 -0
  83. package/docs/specs/012-ollama-cli-overlay/spec.md +47 -0
  84. package/docs/specs/013-doctor-dependency-check/spec.md +250 -0
  85. package/docs/specs/014-doctor-compose-port-cross-validation/spec.md +276 -0
  86. package/docs/specs/015-doctor-env-example-drift/spec.md +248 -0
  87. package/docs/specs/016-doctor-reproducibility-check/spec.md +276 -0
  88. package/docs/specs/017-doctor-dry-run/spec.md +276 -0
  89. package/docs/specs/018-init-project-file/spec.md +59 -0
  90. package/docs/specs/taxonomy.md +186 -0
  91. package/overlays/.presets/full-observability.yml +113 -0
  92. package/overlays/.presets/k8s-dev.yml +174 -0
  93. package/overlays/.presets/local-llm.yml +105 -0
  94. package/overlays/.presets/vector-ai.yml +150 -0
  95. package/overlays/.shared/README.md +27 -2
  96. package/overlays/.shared/compose/nvidia-gpu-devcontainer.yml +22 -0
  97. package/overlays/.shared/vscode/js-ts-settings.json +19 -0
  98. package/overlays/.shared/vscode/markdown-extensions.json +8 -0
  99. package/overlays/alertmanager/devcontainer.patch.json +0 -1
  100. package/overlays/alertmanager/docker-compose.yml +8 -0
  101. package/overlays/alertmanager/overlay.yml +1 -0
  102. package/overlays/amp/devcontainer.patch.json +4 -1
  103. package/overlays/bun/devcontainer.patch.json +1 -10
  104. package/overlays/bun/overlay.yml +8 -1
  105. package/overlays/claude-code/devcontainer.patch.json +6 -1
  106. package/overlays/codex/devcontainer.patch.json +5 -0
  107. package/overlays/comfyui/.env.example +34 -0
  108. package/overlays/comfyui/README.md +342 -0
  109. package/overlays/comfyui/devcontainer.patch.json +15 -0
  110. package/overlays/comfyui/docker-compose.yml +40 -0
  111. package/overlays/comfyui/overlay.yml +24 -0
  112. package/overlays/comfyui/setup.sh +36 -0
  113. package/overlays/comfyui/verify.sh +103 -0
  114. package/overlays/commitlint/devcontainer.patch.json +1 -6
  115. package/overlays/docker-sock/overlay.yml +1 -0
  116. package/overlays/dotnet/overlay.yml +4 -1
  117. package/overlays/fuseki/.env.example +5 -0
  118. package/overlays/fuseki/README.md +173 -0
  119. package/overlays/fuseki/devcontainer.patch.json +18 -0
  120. package/overlays/fuseki/docker-compose.yml +29 -0
  121. package/overlays/fuseki/overlay.yml +42 -0
  122. package/overlays/fuseki/verify.sh +58 -0
  123. package/overlays/gemini-cli/devcontainer.patch.json +4 -1
  124. package/overlays/go/overlay.yml +6 -1
  125. package/overlays/grafana/devcontainer.patch.json +0 -1
  126. package/overlays/grafana/docker-compose.yml +8 -2
  127. package/overlays/grafana/overlay.yml +6 -1
  128. package/overlays/jaeger/.env.example +11 -0
  129. package/overlays/jaeger/README.md +33 -4
  130. package/overlays/jaeger/devcontainer.patch.json +9 -1
  131. package/overlays/jaeger/docker-compose.yml +17 -0
  132. package/overlays/jaeger/overlay.yml +1 -12
  133. package/overlays/java/overlay.yml +6 -1
  134. package/overlays/jupyter/docker-compose.yml +1 -0
  135. package/overlays/jupyter/overlay.yml +1 -0
  136. package/overlays/k3d/README.md +201 -0
  137. package/overlays/k3d/devcontainer.patch.json +9 -0
  138. package/overlays/k3d/overlay.yml +19 -0
  139. package/overlays/k3d/setup.sh +34 -0
  140. package/overlays/k3d/verify.sh +38 -0
  141. package/overlays/keycloak/devcontainer.patch.json +0 -1
  142. package/overlays/keycloak/docker-compose.yml +1 -0
  143. package/overlays/keycloak/overlay.yml +15 -0
  144. package/overlays/localstack/docker-compose.yml +1 -0
  145. package/overlays/localstack/overlay.yml +19 -1
  146. package/overlays/loki/devcontainer.patch.json +0 -1
  147. package/overlays/loki/docker-compose.yml +8 -0
  148. package/overlays/loki/overlay.yml +1 -0
  149. package/overlays/mailpit/docker-compose.yml +1 -0
  150. package/overlays/mailpit/overlay.yml +1 -0
  151. package/overlays/minio/devcontainer.patch.json +1 -1
  152. package/overlays/minio/docker-compose.yml +1 -0
  153. package/overlays/minio/overlay.yml +23 -2
  154. package/overlays/mkdocs/devcontainer.patch.json +1 -5
  155. package/overlays/mkdocs/overlay.yml +3 -1
  156. package/overlays/mkdocs2/devcontainer.patch.json +1 -5
  157. package/overlays/mkdocs2/overlay.yml +2 -0
  158. package/overlays/mongodb/docker-compose.yml +2 -0
  159. package/overlays/mongodb/overlay.yml +26 -2
  160. package/overlays/mysql/docker-compose.yml +2 -0
  161. package/overlays/mysql/overlay.yml +36 -2
  162. package/overlays/nats/docker-compose.yml +1 -0
  163. package/overlays/nats/overlay.yml +18 -2
  164. package/overlays/nodejs/devcontainer.patch.json +1 -12
  165. package/overlays/nodejs/overlay.yml +8 -1
  166. package/overlays/ollama/.env.example +14 -0
  167. package/overlays/ollama/README.md +326 -0
  168. package/overlays/ollama/devcontainer.patch.json +14 -0
  169. package/overlays/ollama/docker-compose.yml +25 -0
  170. package/overlays/ollama/overlay.yml +27 -0
  171. package/overlays/ollama/verify.sh +76 -0
  172. package/overlays/ollama-cli/README.md +90 -0
  173. package/overlays/ollama-cli/devcontainer.patch.json +3 -0
  174. package/overlays/ollama-cli/overlay.yml +19 -0
  175. package/overlays/ollama-cli/setup.sh +103 -0
  176. package/overlays/ollama-cli/verify.sh +49 -0
  177. package/overlays/open-webui/.env.example +5 -0
  178. package/overlays/open-webui/README.md +162 -0
  179. package/overlays/open-webui/devcontainer.patch.json +14 -0
  180. package/overlays/open-webui/docker-compose.yml +24 -0
  181. package/overlays/open-webui/overlay.yml +45 -0
  182. package/overlays/opencode/devcontainer.patch.json +4 -1
  183. package/overlays/otel-collector/README.md +4 -0
  184. package/overlays/otel-collector/devcontainer.patch.json +4 -1
  185. package/overlays/otel-collector/docker-compose.yml +8 -4
  186. package/overlays/otel-collector/overlay.yml +1 -0
  187. package/overlays/otel-demo-nodejs/devcontainer.patch.json +0 -1
  188. package/overlays/otel-demo-nodejs/docker-compose.yml +1 -0
  189. package/overlays/otel-demo-nodejs/overlay.yml +9 -1
  190. package/overlays/otel-demo-python/devcontainer.patch.json +0 -1
  191. package/overlays/otel-demo-python/docker-compose.yml +1 -0
  192. package/overlays/otel-demo-python/overlay.yml +6 -1
  193. package/overlays/pandoc/README.md +10 -0
  194. package/overlays/pandoc/devcontainer.patch.json +0 -5
  195. package/overlays/pandoc/overlay.yml +2 -0
  196. package/overlays/pandoc/setup.sh +10 -0
  197. package/overlays/pgvector/.env.example +6 -0
  198. package/overlays/pgvector/README.md +215 -0
  199. package/overlays/pgvector/devcontainer.patch.json +29 -0
  200. package/overlays/pgvector/docker-compose.yml +33 -0
  201. package/overlays/pgvector/overlay.yml +47 -0
  202. package/overlays/playwright/devcontainer.patch.json +0 -5
  203. package/overlays/playwright/overlay.yml +2 -1
  204. package/overlays/postgres/.env.example +5 -5
  205. package/overlays/postgres/devcontainer.patch.json +4 -4
  206. package/overlays/postgres/docker-compose.yml +11 -6
  207. package/overlays/postgres/overlay.yml +23 -2
  208. package/overlays/pre-commit/devcontainer.patch.json +1 -7
  209. package/overlays/prometheus/devcontainer.patch.json +0 -1
  210. package/overlays/prometheus/docker-compose.yml +8 -0
  211. package/overlays/prometheus/overlay.yml +1 -0
  212. package/overlays/promtail/devcontainer.patch.json +1 -2
  213. package/overlays/promtail/docker-compose.yml +8 -0
  214. package/overlays/promtail/overlay.yml +1 -0
  215. package/overlays/qdrant/.env.example +4 -0
  216. package/overlays/qdrant/README.md +216 -0
  217. package/overlays/qdrant/devcontainer.patch.json +20 -0
  218. package/overlays/qdrant/docker-compose.yml +26 -0
  219. package/overlays/qdrant/overlay.yml +44 -0
  220. package/overlays/rabbitmq/docker-compose.yml +1 -0
  221. package/overlays/rabbitmq/overlay.yml +25 -2
  222. package/overlays/redis/docker-compose.yml +7 -0
  223. package/overlays/redis/overlay.yml +15 -1
  224. package/overlays/redpanda/docker-compose.yml +1 -0
  225. package/overlays/redpanda/overlay.yml +15 -3
  226. package/overlays/rocm/overlay.yml +2 -1
  227. package/overlays/rust/overlay.yml +3 -1
  228. package/overlays/skaffold/README.md +256 -0
  229. package/overlays/skaffold/devcontainer.patch.json +9 -0
  230. package/overlays/skaffold/overlay.yml +20 -0
  231. package/overlays/skaffold/setup.sh +33 -0
  232. package/overlays/skaffold/verify.sh +24 -0
  233. package/overlays/sqlserver/docker-compose.yml +1 -0
  234. package/overlays/sqlserver/overlay.yml +17 -0
  235. package/overlays/tempo/devcontainer.patch.json +0 -1
  236. package/overlays/tempo/docker-compose.yml +8 -0
  237. package/overlays/tempo/overlay.yml +1 -0
  238. package/overlays/windsurf-cli/devcontainer.patch.json +4 -1
  239. package/package.json +3 -2
  240. package/tool/schema/config.schema.json +31 -1
  241. package/tool/schema/overlay-manifest.schema.json +33 -0
  242. package/overlays/.shared/otel/otel-base-config.yaml +0 -30
@@ -1,18 +1,11 @@
1
1
  # Feature Specification: MkDocs 2.x Overlay
2
2
 
3
- **Feature Branch**: `copilot/add-mkdocs2-overlay`
3
+ **Spec ID**: `003-mkdocs2-overlay`
4
4
  **Created**: 2026-03-16
5
5
  **Status**: Final
6
6
  **Input**: Add a new `mkdocs2` overlay that installs MkDocs 2.x with the Material theme via direct `pip` install, keeping the existing `mkdocs` (MkDocs 1.x) overlay untouched for backward compatibility.
7
7
 
8
- ## Review & Approval _(mandatory before implementation)_
9
-
10
- - **Spec Path**: `docs/specs/003-mkdocs2-overlay/spec.md`
11
- - **Commit Status**: Committed
12
- - **Review Status**: Approved
13
- - **Implementation Gate**: No implementation code may begin until this spec is committed and reviewed.
14
-
15
- ## User Scenarios & Testing _(mandatory)_
8
+ ## User Scenarios & Testing
16
9
 
17
10
  ### User Story 1 - Use MkDocs 2.x in a devcontainer (Priority: P1)
18
11
 
@@ -1,17 +1,10 @@
1
1
  # Feature Specification: `doctor --fix` — Interactive Auto-Repair
2
2
 
3
- **Feature Branch**: `004-doctor-fix`
3
+ **Spec ID**: `004-doctor-fix`
4
4
  **Created**: 2026-03-19
5
5
  **Status**: Final
6
6
  **Input**: GitHub issue: Implement `doctor --fix` — interactive auto-repair for environment issues
7
7
 
8
- ## Review & Approval _(mandatory before implementation)_
9
-
10
- - **Spec Path**: `docs/specs/004-doctor-fix/spec.md`
11
- - **Commit Status**: Committed
12
- - **Review Status**: APPROVED
13
- - **Implementation Gate**: No implementation code may begin until this spec is committed and reviewed.
14
-
15
8
  ## Summary
16
9
 
17
10
  The `doctor` command validates the environment. The `--fix` path was a placeholder. This spec
@@ -1,18 +1,11 @@
1
1
  # Feature Specification: CUDA (NVIDIA GPU) Overlay
2
2
 
3
- **Feature Branch**: `copilot/add-cuda-overlay-for-gpu`
3
+ **Spec ID**: `005-cuda-overlay`
4
4
  **Created**: 2026-03-22
5
5
  **Status**: Final
6
6
  **Input**: Add a `cuda` overlay to enable NVIDIA GPU-accelerated workloads inside a dev container.
7
7
 
8
- ## Review & Approval _(mandatory before implementation)_
9
-
10
- - **Spec Path**: `docs/specs/005-cuda-overlay/spec.md`
11
- - **Commit Status**: Committed
12
- - **Review Status**: Approved
13
- - **Implementation Gate**: No implementation code may begin until this spec is committed and reviewed.
14
-
15
- ## User Scenarios & Testing _(mandatory)_
8
+ ## User Scenarios & Testing
16
9
 
17
10
  ### User Story 1 - GPU passthrough for ML/inference workloads (Priority: P1)
18
11
 
@@ -1,24 +1,17 @@
1
1
  # Feature Specification: ROCm (AMD GPU) Overlay
2
2
 
3
- **Feature Branch**: `copilot/add-rocm-overlay`
3
+ **Spec ID**: `006-rocm-overlay`
4
4
  **Created**: 2026-03-22
5
- **Status**: Accepted
5
+ **Status**: Final
6
6
  **Input**: Add a `rocm` overlay to enable AMD GPU-accelerated workloads inside a dev container.
7
7
 
8
- ## Review & Approval _(mandatory before implementation)_
9
-
10
- - **Spec Path**: `docs/specs/006-rocm-overlay/spec.md`
11
- - **Commit Status**: Committed
12
- - **Review Status**: Approved
13
- - **Implementation Gate**: No implementation code may begin until this spec is committed and reviewed.
14
-
15
8
  ## Overview
16
9
 
17
10
  Add a `rocm` overlay to enable AMD GPU-accelerated workloads inside a dev container using the ROCm open software platform.
18
11
 
19
12
  > **Note:** ROCm-in-container is a supported but more fragile path than CUDA. It depends heavily on the host kernel version, AMD driver stack, specific device support, and container runtime configuration. Treat this as a separate supported profile — not a drop-in equivalent of CUDA.
20
13
 
21
- ## User Scenarios & Testing _(mandatory)_
14
+ ## User Scenarios & Testing
22
15
 
23
16
  ### User Story 1 - AMD GPU passthrough for ML/inference workloads (Priority: P1)
24
17
 
@@ -0,0 +1,119 @@
1
+ # Feature Specification: Target-Aware Generation
2
+
3
+ **Spec ID**: `007-target-aware-generation`
4
+ **Created**: 2026-03-23
5
+ **Status**: Final
6
+ **Input**: Issue [feat] Target-aware generation — produce workspace artifacts and guidance for codespaces, gitpod, and devpod
7
+
8
+ ## User Scenarios & Testing
9
+
10
+ ### User Story 1 — Generate codespaces artifacts (Priority: P1)
11
+
12
+ A user generates with `--target codespaces` and expects to receive Codespaces-specific files and
13
+ guidance alongside the normal devcontainer output.
14
+
15
+ **Acceptance:**
16
+
17
+ 1. `--target codespaces` → `devcontainer.json` extended with `hostRequirements`, `CODESPACES.md` written to `.devcontainer/`.
18
+ 2. `--target local` or no `--target` → no `CODESPACES.md`, no `hostRequirements` in devcontainer.
19
+
20
+ ### User Story 2 — Generate gitpod artifacts (Priority: P1)
21
+
22
+ A user generates with `--target gitpod` and expects a `.gitpod.yml` in the project root and
23
+ setup guidance inside `.devcontainer/`.
24
+
25
+ **Acceptance:**
26
+
27
+ 1. `--target gitpod` → `.gitpod.yml` at project root with tasks and port exposures from selected overlays; `GITPOD.md` written to `.devcontainer/`.
28
+ 2. `--target local` → no `.gitpod.yml`, no `GITPOD.md`.
29
+
30
+ ### User Story 3 — Generate devpod artifacts (Priority: P1)
31
+
32
+ A user generates with `--target devpod` and expects a `devpod.yaml` at the project root and
33
+ setup guidance inside `.devcontainer/`.
34
+
35
+ **Acceptance:**
36
+
37
+ 1. `--target devpod` → `devpod.yaml` at project root; `DEVPOD.md` written to `.devcontainer/`.
38
+ 2. `--target local` → no `devpod.yaml`, no `DEVPOD.md`.
39
+
40
+ ### User Story 4 — Local generation unchanged (Priority: P1)
41
+
42
+ When a user generates without specifying a target, or with `--target local`, the output must
43
+ not contain any non-local artifacts.
44
+
45
+ **Acceptance:**
46
+
47
+ 1. No `--target` flag → output identical to current behavior; no new files written.
48
+ 2. `--target local` (explicit) → same output as omitting `--target`.
49
+
50
+ ### User Story 5 — Regeneration from manifest with target (Priority: P2)
51
+
52
+ A user regenerates from an existing `superposition.json` that includes `"target": "gitpod"` and
53
+ expects the same Gitpod-specific artifacts without being prompted again.
54
+
55
+ **Acceptance:**
56
+
57
+ 1. Manifest with `target: gitpod` → regen produces `.gitpod.yml` and `GITPOD.md`.
58
+ 2. Manifest with no `target` or `target: local` → regen produces no target-specific artifacts.
59
+
60
+ ### User Story 6 — Target switching cleans up stale artifacts (Priority: P2)
61
+
62
+ A user regenerates with a different `--target` value and expects the previous target's
63
+ project-root artifacts to be removed.
64
+
65
+ **Acceptance:**
66
+
67
+ 1. Previous run was `--target gitpod` (`.gitpod.yml` exists); regeneration with `--target codespaces` → `.gitpod.yml` removed, `CODESPACES.md` written.
68
+ 2. Previous run was `--target devpod`; regeneration with `--target local` → `devpod.yaml` removed.
69
+
70
+ ## Technical Design
71
+
72
+ ### `TargetRule` interface
73
+
74
+ A `TargetRule` encapsulates everything about generating artifacts for one deployment target:
75
+
76
+ ```typescript
77
+ interface TargetRule {
78
+ target: DeploymentTarget;
79
+ /** Extra fields merged into devcontainer.json */
80
+ devcontainerPatch(context: TargetRuleContext): Partial<DevContainer>;
81
+ /** Files to write; keys are relative to outputPath, '../<name>' writes to project root */
82
+ generateFiles(context: TargetRuleContext): Map<string, string>;
83
+ /** All relative paths owned by this rule (for stale-cleanup on target switch) */
84
+ ownedFiles(): string[];
85
+ }
86
+ ```
87
+
88
+ ### Per-target rules
89
+
90
+ | Target | devcontainer.json change | Files in `.devcontainer/` | Files at project root |
91
+ | ------------ | ------------------------ | ------------------------- | --------------------- |
92
+ | `local` | none | none | none |
93
+ | `codespaces` | `hostRequirements` | `CODESPACES.md` | none |
94
+ | `gitpod` | none | `GITPOD.md` | `.gitpod.yml` |
95
+ | `devpod` | none | `DEVPOD.md` | `devpod.yaml` |
96
+
97
+ ### `SuperpositionManifest` update
98
+
99
+ Add `target?: DeploymentTarget` so regeneration reproduces the correct artifacts without
100
+ re-prompting.
101
+
102
+ ### Stale-artifact cleanup
103
+
104
+ On each generation, before writing new target artifacts:
105
+
106
+ 1. Read existing `superposition.json` from `outputPath` (if it exists).
107
+ 2. If `manifest.target !== answers.target`, identify previous target's owned project-root
108
+ files (e.g., `.gitpod.yml`) and remove them from the project root.
109
+
110
+ The `.devcontainer/`-local files are already handled by `cleanupStaleFiles` via `FileRegistry`.
111
+
112
+ ## Functional Requirements (from issue)
113
+
114
+ - **FR-001**: Target is a real generation input that changes produced artifacts.
115
+ - **FR-002**: `codespaces`, `gitpod`, `devpod` produce target-specific workspace artifacts.
116
+ - **FR-003**: `local` (explicit or default) produces no additional artifacts.
117
+ - **FR-009**: Regeneration from manifest reproduces target-aware output automatically.
118
+ - **FR-010**: Target switch between runs removes stale artifacts from the previous target.
119
+ - **FR-011**: Backward compatible — manifests without `target` or with `target: local` unchanged.
@@ -0,0 +1,82 @@
1
+ # Feature Specification: Make superposition.yml the Canonical Input
2
+
3
+ **Spec ID**: `008-project-file-canonical`
4
+ **Created**: 2026-03-26
5
+ **Author**: PM Agent
6
+ **Status**: Approved
7
+ **Input**: GitHub issue #134 — make `superposition.yml` the required canonical input for all generation flows
8
+
9
+ ## Overview
10
+
11
+ Make `superposition.yml` (the project config file) the required, canonical input for all
12
+ generation and regeneration flows. `superposition.json` (the manifest) becomes an output-only
13
+ artifact — a generated receipt, not an input source.
14
+
15
+ ## Motivation
16
+
17
+ Three entry points currently disagree on which file is authoritative, creating user confusion
18
+ and dead code paths. The newest code path (`generate`) already writes `superposition.yml`
19
+ first. This spec promotes that pattern to all entry points.
20
+
21
+ ## Behavioral Changes
22
+
23
+ ### `init` — Always writes `superposition.yml`
24
+
25
+ - Remove `--project-file` flag; writing the project config is now the default.
26
+ - Add `--no-scaffold` flag to skip generating `.devcontainer/` (for project-file-only runs).
27
+ - Scaffold (`.devcontainer/` generation) remains the default for backward compatibility.
28
+ - The project file is written before scaffolding; a scaffold failure does not lose the config.
29
+
30
+ ### `regen` — Reads `superposition.yml` only
31
+
32
+ - Default input: the project config file auto-discovered in the repository root.
33
+ - `--from-manifest <path>` is retained as a **deprecated hidden flag** that emits a warning
34
+ pointing toward `cs migrate`. Existing CI scripts that rely on it will still work but
35
+ receive a deprecation notice.
36
+ - If no project file exists and `superposition.json` is present: error with actionable
37
+ migration guidance: `Run 'cs migrate' to create a project file from your existing manifest.`
38
+ - If neither file exists: error with creation guidance.
39
+
40
+ ### `superposition.json` — Output only
41
+
42
+ - Still written by `composeDevContainer` / `generateManifestOnly` as before.
43
+ - No longer read as a generation input in the standard flow.
44
+ - Still read by `doctor` for diagnostics and drift detection.
45
+
46
+ ## New Commands
47
+
48
+ ### `cs migrate`
49
+
50
+ One-time migration from manifest-only repositories:
51
+
52
+ 1. Discovers or accepts `--from-manifest <path>` to locate `superposition.json`.
53
+ 2. Loads and validates the manifest (with auto-migration for old versions).
54
+ 3. Converts manifest to `ProjectConfigSelection` via the existing
55
+ `buildAnswersFromManifest → mergeAnswers → buildProjectConfigSelectionFromAnswers` pipeline.
56
+ 4. Discovers the output path for the project file (uses existing file if present, otherwise
57
+ defaults to `.superposition.yml`); `--force` to overwrite.
58
+ 5. Writes the project config YAML.
59
+ 6. Prints a success message with next-step guidance (`regen` to regenerate).
60
+
61
+ ## `doctor` Drift Detection
62
+
63
+ Once the project file is canonical, `doctor` can compare the two files:
64
+
65
+ - Load project file overlays (via `loadProjectConfig`).
66
+ - Load last-generated manifest overlays (via existing manifest loading).
67
+ - Report a new `project-file-drift` finding when the overlay sets differ.
68
+ - Suggest `regen` to reconcile.
69
+
70
+ ## Migration Considerations
71
+
72
+ | Repo state | Impact | Action |
73
+ | ----------------------------- | --------------------------------- | -------------------------------- |
74
+ | Has `superposition.yml` only | None — already correct | — |
75
+ | Has `superposition.json` only | `regen` errors | Run `cs migrate` once |
76
+ | Has both (consistent) | None — regen prefers project file | — |
77
+ | CI using `--from-manifest` | Warning on each run | Switch to `cs migrate` + `regen` |
78
+
79
+ ## Notes
80
+
81
+ Implementation proceeds with this spec committed. No further approval required for the
82
+ behavioral changes listed above.
@@ -0,0 +1,140 @@
1
+ # Feature Specification: Unified Project-Level Environment Variables
2
+
3
+ **Spec ID**: `009-project-env`
4
+ **Created**: 2026-03-29
5
+ **Status**: Approved
6
+ **Input**: User request
7
+
8
+ ## User Scenarios & Testing
9
+
10
+ ### User Story 1 — Define environment variables once for plain stack (Priority: P1)
11
+
12
+ A developer adds an `env:` block to `superposition.yml` on a `plain` stack and expects the
13
+ variables to appear in `devcontainer.json → remoteEnv` after regeneration.
14
+
15
+ **Why this priority**: The most common use case is a plain-stack project needing a handful of
16
+ environment variables visible inside the devcontainer without manually editing JSON files.
17
+
18
+ **Independent Test**: Create a `superposition.yml` with `stack: plain` and `env: {APP_NAME: my-app}`,
19
+ run `regen`, and confirm that `devcontainer.json` contains `"remoteEnv": {"APP_NAME": "my-app"}`.
20
+
21
+ **Acceptance Scenarios**:
22
+
23
+ 1. **Given** `superposition.yml` has `env: {APP_NAME: my-app}`, **When** generation runs with `stack: plain`, **Then** `devcontainer.json` includes `remoteEnv.APP_NAME: my-app`.
24
+ 2. **Given** `env:` uses the long form (`{value: "foo", target: auto}` — an object with a required `value` string and optional `target` routing hint), **When** generation runs with `stack: plain`, **Then** the variable is written to `remoteEnv` identical to the string shorthand.
25
+
26
+ ---
27
+
28
+ ### User Story 2 — Define environment variables once for compose stack (Priority: P1)
29
+
30
+ A developer adds an `env:` block to `superposition.yml` on a `compose` stack and expects the
31
+ variables to appear in `docker-compose.yml → services.devcontainer.environment` after regeneration.
32
+
33
+ **Why this priority**: Compose-stack users currently must split env configuration across
34
+ `customizations.devcontainerPatch.remoteEnv` and `customizations.dockerComposePatch`, which is
35
+ error-prone and hard to discover.
36
+
37
+ **Independent Test**: Create a `superposition.yml` with `stack: compose` and
38
+ `env: {DB_HOST: postgres}`, run `regen`, and confirm the variable appears under
39
+ `services.devcontainer.environment` in the generated `docker-compose.yml`.
40
+
41
+ **Acceptance Scenarios**:
42
+
43
+ 1. **Given** `superposition.yml` has `env: {DB_HOST: postgres}` on a compose stack, **When** generation runs, **Then** `docker-compose.yml` contains `services.devcontainer.environment.DB_HOST: postgres`.
44
+ 2. **Given** `target: composeEnv` is specified, **When** generation runs with `stack: plain`, **Then** generation errors with a clear message about compose-only targets.
45
+
46
+ ---
47
+
48
+ ### User Story 3 — Explicit target overrides auto-routing (Priority: P2)
49
+
50
+ A developer uses `target: remoteEnv` on a compose-stack project to force a variable into
51
+ `devcontainer.json` instead of `docker-compose.yml`.
52
+
53
+ **Why this priority**: Power users occasionally need fine-grained control over where a variable
54
+ lands, especially for VS Code-specific settings that must be in `remoteEnv`.
55
+
56
+ **Independent Test**: Set `target: remoteEnv` on a variable in a compose-stack project, run
57
+ `regen`, and confirm the variable is in `devcontainer.json → remoteEnv` (not in
58
+ `docker-compose.yml → services.devcontainer.environment`).
59
+
60
+ **Acceptance Scenarios**:
61
+
62
+ 1. **Given** `{value: "bar", target: remoteEnv}` in `env:` on a compose stack, **When** generation runs, **Then** the variable is written to `devcontainer.json → remoteEnv` only.
63
+
64
+ ---
65
+
66
+ ## Overview
67
+
68
+ Add a first-class `env` field to `superposition.yml` so a project can define
69
+ environment variables once and have them land in the correct generated output:
70
+
71
+ - `remoteEnv` for `plain` stacks
72
+ - `services.devcontainer.environment` in `docker-compose.yml` for `compose` stacks
73
+
74
+ This removes the need to split simple container environment variables across
75
+ `customizations.devcontainerPatch.remoteEnv` and
76
+ `customizations.dockerComposePatch`.
77
+
78
+ ## Project File Shape
79
+
80
+ ```yaml
81
+ env:
82
+ APP_NAME: my-app
83
+ API_BASE_URL:
84
+ value: ${API_BASE_URL:-http://localhost:3000}
85
+ target: auto
86
+ ```
87
+
88
+ Rules:
89
+
90
+ - `env` is a map keyed by variable name.
91
+ - A value may be:
92
+ - a string shorthand, equivalent to `{ value: "<string>", target: auto }`
93
+ - an object with:
94
+ - `value: string` required
95
+ - `target: auto | remoteEnv | composeEnv` optional, default `auto`
96
+
97
+ ## Generation Behavior
98
+
99
+ ### `target: auto`
100
+
101
+ - `plain` stack: write the variable to `devcontainer.json -> remoteEnv`
102
+ - `compose` stack: write the variable to
103
+ `docker-compose.yml -> services.devcontainer.environment`
104
+
105
+ ### Explicit targets
106
+
107
+ - `remoteEnv`: always write to `devcontainer.json -> remoteEnv`
108
+ - `composeEnv`: write to `docker-compose.yml -> services.devcontainer.environment`
109
+ and error on non-compose stacks
110
+
111
+ ### Precedence
112
+
113
+ - Project-level `env` is applied before `customizations.devcontainerPatch` and
114
+ `customizations.dockerComposePatch`.
115
+ - Custom patch files remain the escape hatch and may override project-level env.
116
+
117
+ ## Root `.env` Expansion Bridge
118
+
119
+ When a compose-targeted project env value references `${NAME}` or
120
+ `${NAME:-default}`, generation should preserve that expression in
121
+ `docker-compose.yml` and also mirror matching keys from the project root `.env`
122
+ into `.devcontainer/.env`.
123
+
124
+ This allows:
125
+
126
+ 1. the repository root `.env` to remain the human-edited source of truth
127
+ 2. Docker Compose to resolve variables from `.devcontainer/.env`
128
+ 3. generated `docker-compose.yml` to avoid embedding resolved secret values
129
+
130
+ Bridge rules:
131
+
132
+ - only referenced variable names are copied
133
+ - existing unrelated entries in `.devcontainer/.env` are preserved
134
+ - missing root variables are not invented; Docker Compose defaults still work
135
+
136
+ ## Non-Goals
137
+
138
+ - No new syntax for targeting arbitrary non-devcontainer services
139
+ - No replacement for advanced compose patches; those remain under
140
+ `customizations.dockerComposePatch`
@@ -0,0 +1,123 @@
1
+ # Feature Specification: Compose Env Materialization and Env Template Naming
2
+
3
+ **Spec ID**: `010-compose-env-materialization`
4
+ **Created**: 2026-03-29
5
+ **Status**: Approved
6
+ **Input**: User request
7
+
8
+ ## User Scenarios & Testing
9
+
10
+ ### User Story 1 — Compose env values materialize into .devcontainer/.env (Priority: P1)
11
+
12
+ A developer sets concrete env values in `superposition.yml` on a `compose` stack and expects
13
+ them to be written to `.devcontainer/.env` (not embedded in `docker-compose.yml`) so that
14
+ secrets are not committed to source control inside generated YAML.
15
+
16
+ **Why this priority**: Embedding resolved values directly in `docker-compose.yml` would expose
17
+ secrets or host-specific values in generated files that are typically committed to source control.
18
+ Materializing them into `.devcontainer/.env` keeps generated config template-only.
19
+
20
+ **Independent Test**: Set `env: {SECRET_KEY: supersecret}` on a compose-stack project, run
21
+ `regen`, and confirm: (a) `docker-compose.yml` contains
22
+ `services.devcontainer.environment.SECRET_KEY: ${SECRET_KEY}`, (b) `.devcontainer/.env` contains
23
+ `SECRET_KEY=supersecret`, and (c) the literal value `supersecret` does not appear in
24
+ `docker-compose.yml`.
25
+
26
+ **Acceptance Scenarios**:
27
+
28
+ 1. **Given** `env: {API_KEY: abc123}` on a compose stack, **When** generation runs, **Then** `docker-compose.yml` has `API_KEY: ${API_KEY}` and `.devcontainer/.env` has `API_KEY=abc123`.
29
+ 2. **Given** `env: {NAME: ${NAME:-default}}`, **When** generation runs with a root `.env` that sets `NAME=prod`, **Then** `.devcontainer/.env` receives `NAME=prod`.
30
+ 3. **Given** `env: {NAME: ${NAME}}` and no root `.env` entry for `NAME`, **When** generation runs, **Then** `.devcontainer/.env` does not include `NAME=` and Docker Compose shell fallback still works.
31
+
32
+ ---
33
+
34
+ ### User Story 2 — Configure env template entries with clearly named project-file field (Priority: P1)
35
+
36
+ A developer updates their `superposition.yml` to use `customizations.envTemplate` (instead of
37
+ the previously named `customizations.environment`) and expects the generated `.env.example`
38
+ content to be identical to what the old field produced.
39
+
40
+ **Why this priority**: The existing `environment` key is misleading — it writes to `.env.example`
41
+ (a template), not to the runtime container environment. Renaming it clarifies intent and prevents
42
+ confusion with the new `env:` field.
43
+
44
+ **Independent Test**: Replace `customizations.environment` with `customizations.envTemplate` in a
45
+ project file, run `regen`, and confirm the generated `.env.example` is byte-for-byte identical to
46
+ the output produced with the old key.
47
+
48
+ **Acceptance Scenarios**:
49
+
50
+ 1. **Given** `customizations.envTemplate: {FOO: bar}`, **When** generation runs, **Then** `.devcontainer/.env.example` contains `FOO=bar`.
51
+ 2. **Given** `customizations.environment: {FOO: bar}` (deprecated alias), **When** generation runs, **Then** `.devcontainer/.env.example` still contains `FOO=bar` (backward-compatible).
52
+ 3. **Given** a project file using `environment`, **When** it is read by the project loader, **Then** a deprecation warning is emitted directing users to rename the key.
53
+
54
+ ---
55
+
56
+ ### User Story 3 — remoteEnv wiring for compose env entries (Priority: P2)
57
+
58
+ A developer on a compose stack expects that compose-targeted env variables are also accessible
59
+ via `${containerEnv:KEY}` in `devcontainer.json → remoteEnv` so VS Code settings and
60
+ extensions can reference them.
61
+
62
+ **Why this priority**: Without a `remoteEnv` entry, VS Code extensions that read `process.env`
63
+ at startup may not see the variable, even though the container process will.
64
+
65
+ **Independent Test**: Set a compose-stack env variable, run `regen`, and confirm
66
+ `devcontainer.json → remoteEnv` includes `KEY: ${containerEnv:KEY}` alongside the
67
+ `docker-compose.yml` entry.
68
+
69
+ **Acceptance Scenarios**:
70
+
71
+ 1. **Given** `env: {DB_URL: postgres://localhost/dev}` on a compose stack, **When** generation runs, **Then** `devcontainer.json` contains `remoteEnv.DB_URL: ${containerEnv:DB_URL}`.
72
+
73
+ ---
74
+
75
+ ## Overview
76
+
77
+ Refine project-file environment semantics so compose-based projects do not
78
+ embed resolved env values directly in generated `docker-compose.yml` or
79
+ `devcontainer.json`.
80
+
81
+ At the same time, rename the project-file field
82
+ `customizations.environment` to `customizations.envTemplate` to make its
83
+ purpose explicit: it writes template variables to `.env.example`, not runtime
84
+ container environment.
85
+
86
+ ## Behavior
87
+
88
+ ### `env:` on `stack: compose`
89
+
90
+ For compose-targeted project env entries:
91
+
92
+ 1. Materialize concrete values into `.devcontainer/.env`
93
+ 2. Write `docker-compose.yml -> services.devcontainer.environment.KEY: ${KEY}`
94
+ 3. Write `devcontainer.json -> remoteEnv.KEY: ${containerEnv:KEY}`
95
+
96
+ This keeps generated config free of resolved secret values while still making
97
+ the variables available inside the devcontainer.
98
+
99
+ ### Value Resolution
100
+
101
+ - literals are written as-is to `.devcontainer/.env`
102
+ - `${NAME}` resolves from the repository root `.env` when present
103
+ - `${NAME:-default}` resolves from the repository root `.env`, otherwise uses
104
+ the inline default
105
+ - unresolved `${NAME}` values are omitted from `.devcontainer/.env` so shell
106
+ environment fallback remains possible
107
+
108
+ ### `env:` on `stack: plain`
109
+
110
+ No change: values still land directly in `devcontainer.json -> remoteEnv`.
111
+
112
+ ## `customizations.envTemplate`
113
+
114
+ - `customizations.envTemplate` is the canonical project-file field for values
115
+ that should be written to `.env.example`
116
+ - `customizations.environment` is retained as a deprecated backward-compatible
117
+ alias
118
+ - serializers should emit `envTemplate`
119
+
120
+ ## Non-Goals
121
+
122
+ - no change to `.devcontainer/custom/environment.env`
123
+ - no support for targeting arbitrary compose sidecar services from `env:`