container-superposition 0.1.6 → 0.1.8
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.
- package/README.md +24 -15
- package/dist/scripts/init.js +1 -1534
- package/dist/scripts/init.js.map +1 -1
- package/dist/tool/cli/args.d.ts +20 -0
- package/dist/tool/cli/args.d.ts.map +1 -0
- package/dist/tool/cli/args.js +325 -0
- package/dist/tool/cli/args.js.map +1 -0
- package/dist/tool/cli/run.d.ts +2 -0
- package/dist/tool/cli/run.d.ts.map +1 -0
- package/dist/tool/cli/run.js +318 -0
- package/dist/tool/cli/run.js.map +1 -0
- package/dist/tool/commands/adopt.d.ts.map +1 -1
- package/dist/tool/commands/adopt.js +1 -27
- package/dist/tool/commands/adopt.js.map +1 -1
- package/dist/tool/commands/doctor.d.ts +3 -0
- package/dist/tool/commands/doctor.d.ts.map +1 -1
- package/dist/tool/commands/doctor.js +1068 -70
- package/dist/tool/commands/doctor.js.map +1 -1
- package/dist/tool/commands/explain.d.ts.map +1 -1
- package/dist/tool/commands/explain.js +18 -0
- package/dist/tool/commands/explain.js.map +1 -1
- package/dist/tool/commands/migrate.d.ts +7 -0
- package/dist/tool/commands/migrate.d.ts.map +1 -0
- package/dist/tool/commands/migrate.js +52 -0
- package/dist/tool/commands/migrate.js.map +1 -0
- package/dist/tool/questionnaire/answers.d.ts +16 -0
- package/dist/tool/questionnaire/answers.d.ts.map +1 -0
- package/dist/tool/questionnaire/answers.js +102 -0
- package/dist/tool/questionnaire/answers.js.map +1 -0
- package/dist/tool/questionnaire/composer.d.ts +3 -3
- package/dist/tool/questionnaire/composer.d.ts.map +1 -1
- package/dist/tool/questionnaire/composer.js +902 -37
- package/dist/tool/questionnaire/composer.js.map +1 -1
- package/dist/tool/questionnaire/presets.d.ts +60 -0
- package/dist/tool/questionnaire/presets.d.ts.map +1 -0
- package/dist/tool/questionnaire/presets.js +164 -0
- package/dist/tool/questionnaire/presets.js.map +1 -0
- package/dist/tool/questionnaire/questionnaire.d.ts +10 -0
- package/dist/tool/questionnaire/questionnaire.d.ts.map +1 -0
- package/dist/tool/questionnaire/questionnaire.js +580 -0
- package/dist/tool/questionnaire/questionnaire.js.map +1 -0
- package/dist/tool/schema/manifest-migrations.d.ts +5 -0
- package/dist/tool/schema/manifest-migrations.d.ts.map +1 -1
- package/dist/tool/schema/manifest-migrations.js +45 -0
- package/dist/tool/schema/manifest-migrations.js.map +1 -1
- package/dist/tool/schema/overlay-loader.d.ts.map +1 -1
- package/dist/tool/schema/overlay-loader.js +25 -0
- package/dist/tool/schema/overlay-loader.js.map +1 -1
- package/dist/tool/schema/project-config.d.ts +14 -2
- package/dist/tool/schema/project-config.d.ts.map +1 -1
- package/dist/tool/schema/project-config.js +277 -34
- package/dist/tool/schema/project-config.js.map +1 -1
- package/dist/tool/schema/target-rules.d.ts +78 -0
- package/dist/tool/schema/target-rules.d.ts.map +1 -0
- package/dist/tool/schema/target-rules.js +367 -0
- package/dist/tool/schema/target-rules.js.map +1 -0
- package/dist/tool/schema/types.d.ts +123 -12
- package/dist/tool/schema/types.d.ts.map +1 -1
- package/dist/tool/utils/merge.d.ts.map +1 -1
- package/dist/tool/utils/merge.js +9 -0
- package/dist/tool/utils/merge.js.map +1 -1
- package/dist/tool/utils/parameters.d.ts +76 -0
- package/dist/tool/utils/parameters.d.ts.map +1 -0
- package/dist/tool/utils/parameters.js +125 -0
- package/dist/tool/utils/parameters.js.map +1 -0
- package/dist/tool/utils/paths.d.ts +2 -0
- package/dist/tool/utils/paths.d.ts.map +1 -0
- package/dist/tool/utils/paths.js +31 -0
- package/dist/tool/utils/paths.js.map +1 -0
- package/docs/creating-overlays.md +151 -2
- package/docs/deployment-targets.md +88 -56
- package/docs/examples.md +20 -17
- package/docs/filesystem-contract.md +5 -0
- package/docs/minimal-and-editor.md +65 -5
- package/docs/overlay-imports.md +202 -101
- package/docs/overlays.md +162 -34
- package/docs/quick-reference.md +99 -0
- package/docs/specs/003-mkdocs2-overlay/spec.md +114 -0
- package/docs/specs/004-doctor-fix/spec.md +70 -0
- package/docs/specs/005-cuda-overlay/spec.md +101 -0
- package/docs/specs/006-rocm-overlay/spec.md +109 -0
- package/docs/specs/007-init-project-file/spec.md +66 -0
- package/docs/specs/007-target-aware-generation/spec.md +126 -0
- package/docs/specs/008-project-file-canonical/spec.md +83 -0
- package/docs/specs/009-project-env/spec.md +147 -0
- package/docs/specs/010-compose-env-materialization/spec.md +130 -0
- package/docs/specs/011-overlay-parameters/spec.md +235 -0
- package/overlays/.shared/README.md +105 -21
- package/overlays/.shared/compose/common-healthchecks.md +60 -0
- package/overlays/.shared/compose/nvidia-gpu-devcontainer.yml +22 -0
- package/overlays/.shared/vscode/recommended-extensions.json +15 -11
- package/overlays/alertmanager/setup.sh +4 -19
- package/overlays/alertmanager/verify.sh +8 -9
- package/overlays/all/README.md +43 -0
- package/overlays/all/devcontainer.patch.json +6 -0
- package/overlays/all/overlay.yml +14 -0
- package/overlays/amp/setup.sh +5 -0
- package/overlays/bun/setup.sh +10 -1
- package/overlays/bun/verify.sh +6 -1
- package/overlays/claude-code/setup.sh +5 -0
- package/overlays/cloudflared/setup.sh +9 -12
- package/overlays/codex/README.md +9 -6
- package/overlays/codex/devcontainer.patch.json +7 -1
- package/overlays/codex/setup.sh +5 -0
- package/overlays/codex/verify.sh +8 -0
- package/overlays/comfyui/.env.example +34 -0
- package/overlays/comfyui/README.md +342 -0
- package/overlays/comfyui/devcontainer.patch.json +15 -0
- package/overlays/comfyui/docker-compose.yml +39 -0
- package/overlays/comfyui/overlay.yml +20 -0
- package/overlays/comfyui/setup.sh +36 -0
- package/overlays/comfyui/verify.sh +103 -0
- package/overlays/commitlint/setup.sh +5 -0
- package/overlays/cuda/README.md +179 -0
- package/overlays/cuda/devcontainer.patch.json +7 -0
- package/overlays/cuda/overlay.yml +17 -0
- package/overlays/cuda/setup.sh +32 -0
- package/overlays/cuda/verify.sh +38 -0
- package/overlays/devcontainer-cli/README.md +50 -0
- package/overlays/devcontainer-cli/devcontainer.patch.json +13 -0
- package/overlays/devcontainer-cli/overlay.yml +16 -0
- package/overlays/devcontainer-cli/setup.sh +14 -0
- package/overlays/direnv/devcontainer.patch.json +6 -0
- package/overlays/direnv/setup.sh +7 -6
- package/overlays/dotnet/setup.sh +14 -7
- package/overlays/duckdb/devcontainer.patch.json +1 -2
- package/overlays/gcloud/devcontainer.patch.json +0 -6
- package/overlays/gcloud/setup.sh +51 -0
- package/overlays/gemini-cli/setup.sh +5 -0
- package/overlays/git-helpers/devcontainer.patch.json +2 -1
- package/overlays/go/setup.sh +15 -14
- package/overlays/jaeger/overlay.yml +2 -0
- package/overlays/just/setup.sh +5 -17
- package/overlays/k3d/README.md +201 -0
- package/overlays/k3d/devcontainer.patch.json +9 -0
- package/overlays/k3d/overlay.yml +19 -0
- package/overlays/k3d/setup.sh +34 -0
- package/overlays/k3d/verify.sh +38 -0
- package/overlays/keycloak/docker-compose.yml +6 -4
- package/overlays/keycloak/verify.sh +4 -3
- package/overlays/kind/devcontainer.patch.json +1 -2
- package/overlays/kind/setup.sh +8 -17
- package/overlays/minio/setup.sh +10 -18
- package/overlays/mkdocs/overlay.yml +2 -1
- package/overlays/mkdocs2/README.md +135 -0
- package/overlays/mkdocs2/devcontainer.patch.json +19 -0
- package/overlays/mkdocs2/overlay.yml +17 -0
- package/overlays/mkdocs2/setup.sh +67 -0
- package/overlays/mkdocs2/verify.sh +35 -0
- package/overlays/modern-cli-tools/devcontainer.patch.json +7 -1
- package/overlays/modern-cli-tools/setup.sh +21 -71
- package/overlays/mongodb/devcontainer.patch.json +0 -6
- package/overlays/mongodb/setup.sh +59 -0
- package/overlays/mysql/verify.sh +4 -3
- package/overlays/nats/.env.example +1 -1
- package/overlays/nats/README.md +1 -1
- package/overlays/nats/docker-compose.yml +1 -1
- package/overlays/ngrok/setup.sh +9 -6
- package/overlays/nodejs/setup.sh +5 -0
- package/overlays/ollama/.env.example +14 -0
- package/overlays/ollama/README.md +325 -0
- package/overlays/ollama/devcontainer.patch.json +14 -0
- package/overlays/ollama/docker-compose.yml +24 -0
- package/overlays/ollama/overlay.yml +22 -0
- package/overlays/ollama/setup.sh +106 -0
- package/overlays/ollama/verify.sh +99 -0
- package/overlays/open-webui/.env.example +5 -0
- package/overlays/open-webui/README.md +162 -0
- package/overlays/open-webui/devcontainer.patch.json +14 -0
- package/overlays/open-webui/docker-compose.yml +23 -0
- package/overlays/open-webui/overlay.yml +38 -0
- package/overlays/openapi-tools/devcontainer.patch.json +1 -2
- package/overlays/openapi-tools/setup.sh +9 -8
- package/overlays/opencode/setup.sh +5 -0
- package/overlays/otel-collector/overlay.yml +2 -0
- package/overlays/otel-collector/setup.sh +3 -16
- package/overlays/otel-demo-nodejs/verify.sh +8 -9
- package/overlays/otel-demo-python/verify.sh +16 -10
- package/overlays/pandoc/README.md +22 -15
- package/overlays/pandoc/devcontainer.patch.json +6 -2
- package/overlays/pandoc/setup.sh +217 -18
- package/overlays/pandoc/verify.sh +16 -4
- package/overlays/pgvector/.env.example +6 -0
- package/overlays/pgvector/README.md +215 -0
- package/overlays/pgvector/devcontainer.patch.json +23 -0
- package/overlays/pgvector/docker-compose.yml +32 -0
- package/overlays/pgvector/overlay.yml +44 -0
- package/overlays/playwright/devcontainer.patch.json +3 -1
- package/overlays/playwright/setup.sh +37 -0
- package/overlays/postgres/.env.example +5 -5
- package/overlays/postgres/devcontainer.patch.json +4 -4
- package/overlays/postgres/docker-compose.yml +15 -5
- package/overlays/postgres/overlay.yml +19 -1
- package/overlays/powershell/setup.sh +49 -13
- package/overlays/pre-commit/setup.sh +12 -3
- package/overlays/prometheus/overlay.yml +2 -0
- package/overlays/promtail/verify.sh +16 -10
- package/overlays/pulumi/devcontainer.patch.json +1 -1
- package/overlays/python/setup.sh +28 -9
- package/overlays/python/verify.sh +4 -2
- package/overlays/qdrant/.env.example +4 -0
- package/overlays/qdrant/README.md +216 -0
- package/overlays/qdrant/devcontainer.patch.json +20 -0
- package/overlays/qdrant/docker-compose.yml +25 -0
- package/overlays/qdrant/overlay.yml +40 -0
- package/overlays/redpanda/docker-compose.yml +3 -5
- package/overlays/rocm/README.md +227 -0
- package/overlays/rocm/devcontainer.patch.json +4 -0
- package/overlays/rocm/overlay.yml +17 -0
- package/overlays/rocm/setup.sh +45 -0
- package/overlays/rocm/verify.sh +47 -0
- package/overlays/rust/setup.sh +11 -18
- package/overlays/skaffold/README.md +256 -0
- package/overlays/skaffold/devcontainer.patch.json +9 -0
- package/overlays/skaffold/overlay.yml +20 -0
- package/overlays/skaffold/setup.sh +33 -0
- package/overlays/skaffold/verify.sh +24 -0
- package/overlays/spec-kit/setup.sh +7 -3
- package/overlays/sqlite/setup.sh +14 -14
- package/overlays/sqlserver/docker-compose.yml +3 -3
- package/overlays/sqlserver/verify.sh +22 -5
- package/overlays/tempo/verify.sh +16 -10
- package/overlays/tilt/devcontainer.patch.json +1 -2
- package/overlays/tilt/setup.sh +14 -4
- package/overlays/windsurf-cli/setup.sh +27 -4
- package/overlays/windsurf-cli/verify.sh +13 -3
- package/package.json +4 -2
- package/templates/scripts/setup-utils.sh +228 -0
- package/tool/schema/config.schema.json +141 -9
- package/tool/schema/overlay-manifest.schema.json +38 -0
- package/overlays/.shared/compose/common-healthchecks.yml +0 -38
- /package/overlays/otel-demo-nodejs/{Dockerfile-otel-demo-nodejs → Dockerfile} +0 -0
- /package/overlays/otel-demo-nodejs/{package-otel-demo-nodejs.json → package.json} +0 -0
- /package/overlays/otel-demo-nodejs/{server-otel-demo-nodejs.js → server.js} +0 -0
- /package/overlays/otel-demo-nodejs/{tracing-otel-demo-nodejs.js → tracing.js} +0 -0
- /package/overlays/otel-demo-python/{Dockerfile-otel-demo-python → Dockerfile} +0 -0
- /package/overlays/otel-demo-python/{app-otel-demo-python.py → app.py} +0 -0
- /package/overlays/otel-demo-python/{requirements-otel-demo-python.txt → requirements.txt} +0 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Feature Specification: CUDA (NVIDIA GPU) Overlay
|
|
2
|
+
|
|
3
|
+
**Feature Branch**: `copilot/add-cuda-overlay-for-gpu`
|
|
4
|
+
**Created**: 2026-03-22
|
|
5
|
+
**Status**: Final
|
|
6
|
+
**Input**: Add a `cuda` overlay to enable NVIDIA GPU-accelerated workloads inside a dev container.
|
|
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)_
|
|
16
|
+
|
|
17
|
+
### User Story 1 - GPU passthrough for ML/inference workloads (Priority: P1)
|
|
18
|
+
|
|
19
|
+
A developer wants to run NVIDIA GPU-accelerated workloads (ML training, inference, CUDA compute) inside a dev container without manually configuring Docker runtime flags.
|
|
20
|
+
|
|
21
|
+
**Why this priority**: GPU-accelerated dev containers require specific Docker runtime flags (`--gpus=all`) and VS Code devcontainer host requirements (`gpu: true`) that must be set correctly for the container to access the GPU. Without the overlay, users must add these manually and correctly every time.
|
|
22
|
+
|
|
23
|
+
**Independent Test**: Select the `cuda` overlay, rebuild the container, and confirm that `nvidia-smi` exits 0 and reports the GPU correctly.
|
|
24
|
+
|
|
25
|
+
**Acceptance Scenarios**:
|
|
26
|
+
|
|
27
|
+
1. **Given** a user selects the `cuda` overlay, **When** the devcontainer is built, **Then** `devcontainer.json` includes `"runArgs": ["--gpus=all"]` and `"hostRequirements": {"gpu": true}`.
|
|
28
|
+
2. **Given** the NVIDIA Container Toolkit is installed on the host, **When** the devcontainer starts, **Then** `nvidia-smi` is accessible inside the container.
|
|
29
|
+
3. **Given** the container is running, **When** `setup.sh` executes, **Then** it reports whether `nvidia-smi` is available and prints a helpful message if it is not.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
### User Story 2 - Conflict enforcement between cuda and rocm (Priority: P1)
|
|
34
|
+
|
|
35
|
+
A user selects both `cuda` and `rocm` and expects the tool to report a conflict, because only one GPU compute framework can be active at a time.
|
|
36
|
+
|
|
37
|
+
**Why this priority**: CUDA (NVIDIA) and ROCm (AMD) are mutually exclusive GPU compute frameworks. Allowing both would produce an incoherent configuration.
|
|
38
|
+
|
|
39
|
+
**Independent Test**: Attempt to generate a devcontainer with both `cuda` and `rocm` selected and confirm the tool surfaces a conflict and blocks generation.
|
|
40
|
+
|
|
41
|
+
**Acceptance Scenarios**:
|
|
42
|
+
|
|
43
|
+
1. **Given** a user selects both `cuda` and `rocm`, **When** they run `container-superposition init`, **Then** the tool reports a conflict and prevents generation.
|
|
44
|
+
2. **Given** `cuda` lists `rocm` in `conflicts`, **When** `rocm` is added in the future, **Then** `rocm` must also list `cuda` in its `conflicts` (bidirectional enforcement). Note: `rocm` does not exist yet; when it is added the reciprocal conflict must be declared in `overlays/rocm/overlay.yml`.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Design
|
|
49
|
+
|
|
50
|
+
### overlay.yml
|
|
51
|
+
|
|
52
|
+
```yaml
|
|
53
|
+
id: cuda
|
|
54
|
+
name: CUDA (NVIDIA GPU)
|
|
55
|
+
description: NVIDIA CUDA libraries and GPU passthrough for containerized ML/inference workloads
|
|
56
|
+
category: dev
|
|
57
|
+
supports: []
|
|
58
|
+
requires: []
|
|
59
|
+
suggests: []
|
|
60
|
+
conflicts:
|
|
61
|
+
- rocm
|
|
62
|
+
tags:
|
|
63
|
+
- gpu
|
|
64
|
+
- cuda
|
|
65
|
+
- nvidia
|
|
66
|
+
- ml
|
|
67
|
+
- inference
|
|
68
|
+
ports: []
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### devcontainer.patch.json
|
|
72
|
+
|
|
73
|
+
Set `runArgs` for GPU passthrough and `hostRequirements` to signal GPU need:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"runArgs": ["--gpus=all"],
|
|
78
|
+
"hostRequirements": { "gpu": true }
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### setup.sh
|
|
83
|
+
|
|
84
|
+
- Check whether `nvidia-smi` is reachable inside the container.
|
|
85
|
+
- Print a helpful message if it is not (host driver / toolkit not configured).
|
|
86
|
+
|
|
87
|
+
### verify.sh
|
|
88
|
+
|
|
89
|
+
- Assert `nvidia-smi` exits 0 (used by the `doctor` command).
|
|
90
|
+
|
|
91
|
+
### README.md
|
|
92
|
+
|
|
93
|
+
- Clear prerequisites section (host drivers, NVIDIA Container Toolkit).
|
|
94
|
+
- Troubleshooting tips for common failure modes.
|
|
95
|
+
- Note that the overlay does not replace or install host drivers.
|
|
96
|
+
|
|
97
|
+
## Out of Scope
|
|
98
|
+
|
|
99
|
+
- Installing or replacing host NVIDIA drivers.
|
|
100
|
+
- Guaranteeing version alignment between CUDA user-space libraries and the host kernel module.
|
|
101
|
+
- ROCm (AMD GPU) support — tracked separately.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Feature Specification: ROCm (AMD GPU) Overlay
|
|
2
|
+
|
|
3
|
+
**Feature Branch**: `copilot/add-rocm-overlay`
|
|
4
|
+
**Created**: 2026-03-22
|
|
5
|
+
**Status**: Accepted
|
|
6
|
+
**Input**: Add a `rocm` overlay to enable AMD GPU-accelerated workloads inside a dev container.
|
|
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
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
Add a `rocm` overlay to enable AMD GPU-accelerated workloads inside a dev container using the ROCm open software platform.
|
|
18
|
+
|
|
19
|
+
> **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
|
+
|
|
21
|
+
## User Scenarios & Testing _(mandatory)_
|
|
22
|
+
|
|
23
|
+
### User Story 1 - AMD GPU passthrough for ML/inference workloads (Priority: P1)
|
|
24
|
+
|
|
25
|
+
1. **Given** a user selects the `rocm` overlay, **When** the devcontainer is built, **Then** `devcontainer.json` includes `"runArgs": ["--device=/dev/kfd", "--device=/dev/dri", "--group-add=video", "--group-add=render"]`.
|
|
26
|
+
2. **Given** the AMD GPU drivers and ROCm runtime are installed on the host, **When** the devcontainer starts, **Then** `rocm-smi` is accessible inside the container.
|
|
27
|
+
3. **Given** the container is running, **When** `setup.sh` executes, **Then** it reports whether `rocm-smi` is available and prints a helpful message if it is not.
|
|
28
|
+
4. **Given** `rocm-smi` is not available, **When** `verify.sh` executes, **Then** it exits 1 for the `doctor` command.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Prerequisites (host-side — out of scope for this overlay)
|
|
33
|
+
|
|
34
|
+
1. Supported AMD GPU hardware (RDNA 2+, most CDNA — check [ROCm hardware support matrix](https://rocm.docs.amd.com/en/latest/compatibility/compatibility-matrix.html))
|
|
35
|
+
2. AMD GPU drivers (`amdgpu`) installed on the host
|
|
36
|
+
3. ROCm runtime installed on the host (or the container image bundles it)
|
|
37
|
+
4. User added to the `render` and `video` groups, or appropriate device permissions set
|
|
38
|
+
5. `/dev/kfd` and `/dev/dri` devices accessible in the container
|
|
39
|
+
|
|
40
|
+
## Design
|
|
41
|
+
|
|
42
|
+
### overlay.yml
|
|
43
|
+
|
|
44
|
+
```yaml
|
|
45
|
+
id: rocm
|
|
46
|
+
name: ROCm (AMD GPU)
|
|
47
|
+
description: AMD ROCm libraries and GPU passthrough for containerized ML/inference workloads
|
|
48
|
+
category: dev
|
|
49
|
+
supports: []
|
|
50
|
+
requires: []
|
|
51
|
+
suggests: []
|
|
52
|
+
conflicts:
|
|
53
|
+
- cuda
|
|
54
|
+
tags:
|
|
55
|
+
- dev
|
|
56
|
+
- gpu
|
|
57
|
+
- rocm
|
|
58
|
+
- amd
|
|
59
|
+
- ml
|
|
60
|
+
- inference
|
|
61
|
+
ports: []
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### devcontainer.patch.json
|
|
65
|
+
|
|
66
|
+
Set `runArgs` for AMD GPU device passthrough:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"runArgs": ["--device=/dev/kfd", "--device=/dev/dri", "--group-add=video", "--group-add=render"]
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- `/dev/kfd` — AMD Kernel Fusion Driver; required for ROCm compute
|
|
75
|
+
- `/dev/dri` — Direct Rendering Infrastructure; gives access to GPU render nodes
|
|
76
|
+
- `--group-add=video` and `--group-add=render` — add the container user to the groups that own the GPU device nodes
|
|
77
|
+
|
|
78
|
+
### setup.sh
|
|
79
|
+
|
|
80
|
+
- Check whether `rocm-smi` or `rocminfo` is reachable inside the container.
|
|
81
|
+
- Print a helpful message if neither is found (host driver / ROCm not configured).
|
|
82
|
+
|
|
83
|
+
### verify.sh
|
|
84
|
+
|
|
85
|
+
- Assert `rocm-smi` exits 0 (used by the `doctor` command).
|
|
86
|
+
|
|
87
|
+
### README.md
|
|
88
|
+
|
|
89
|
+
Must include:
|
|
90
|
+
|
|
91
|
+
- Prominent prerequisites section
|
|
92
|
+
- Known limitations (kernel version coupling, device node names may vary)
|
|
93
|
+
- ROCm framework wheels (PyTorch ROCm, TensorFlow ROCm)
|
|
94
|
+
- Troubleshooting section
|
|
95
|
+
- Link to ROCm compatibility matrix
|
|
96
|
+
- Clear note that this overlay does not replace host drivers
|
|
97
|
+
|
|
98
|
+
## Relationship to CUDA Overlay
|
|
99
|
+
|
|
100
|
+
- `cuda` and `rocm` must list each other in `conflicts` (bidirectional, per project rules)
|
|
101
|
+
- The `cuda` overlay already declares `rocm` in its `conflicts`
|
|
102
|
+
- CUDA is considered the primary GPU path; ROCm is a supported secondary path
|
|
103
|
+
|
|
104
|
+
## Known Constraints and Caveats
|
|
105
|
+
|
|
106
|
+
- ROCm version support is tightly coupled to kernel and driver versions
|
|
107
|
+
- Device node names (`/dev/dri/renderD128`) may differ per host
|
|
108
|
+
- Some frameworks publish separate ROCm wheels
|
|
109
|
+
- Less forgiving than CUDA during setup — detailed troubleshooting is essential
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Feature Specification: `init --project-file`
|
|
2
|
+
|
|
3
|
+
**Feature Branch**: `copilot/sub-pr-121`
|
|
4
|
+
**Created**: 2026-03-23
|
|
5
|
+
**Status**: Final
|
|
6
|
+
**Input**: Extend the `init` command with a `--project-file` flag that persists the chosen init configuration into a repository-root project config file (creating `.superposition.yml` by default or updating an existing supported project config), aligning init runs with the project-config workflow.
|
|
7
|
+
|
|
8
|
+
## Review & Approval _(mandatory before implementation)_
|
|
9
|
+
|
|
10
|
+
- **Spec Path**: `docs/specs/007-init-project-file/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
|
+
## Summary
|
|
16
|
+
|
|
17
|
+
Allow `container-superposition init` to optionally write a repository-root
|
|
18
|
+
project config file (`.superposition.yml` by default, or the existing supported
|
|
19
|
+
project config path when one already exists) alongside the normal init output.
|
|
20
|
+
|
|
21
|
+
## Requirements
|
|
22
|
+
|
|
23
|
+
- `init` MUST accept a `--project-file` flag.
|
|
24
|
+
- When `--project-file` is set, `init` MUST write a repository-root project
|
|
25
|
+
config that reflects the final selected configuration for that run.
|
|
26
|
+
- If the repository already contains exactly one supported project config file,
|
|
27
|
+
`init --project-file` MUST update that file instead of creating a second one.
|
|
28
|
+
- If no project config file exists, `init --project-file` MUST write
|
|
29
|
+
`.superposition.yml` at the repository root.
|
|
30
|
+
- The written project config MUST include supported fields represented by the
|
|
31
|
+
final init answers, including stack, base image, overlays, output path,
|
|
32
|
+
target, minimal mode, editor profile, preset, and preset choices.
|
|
33
|
+
- `init --project-file` MUST continue to write `superposition.json` the same way
|
|
34
|
+
current `init` runs do.
|
|
35
|
+
- Project config write errors MUST NOT suppress devcontainer generation success; they MUST be reported separately.
|
|
36
|
+
|
|
37
|
+
## User Scenarios & Testing _(mandatory)_
|
|
38
|
+
|
|
39
|
+
### User Story 1 - Write project config alongside devcontainer generation (Priority: P1)
|
|
40
|
+
|
|
41
|
+
A developer wants to run `init` once and have both a `.devcontainer/` folder and a root-level project config file created, so they can commit the project config and regenerate consistently later.
|
|
42
|
+
|
|
43
|
+
**Why this priority**: The `--project-file` flag is the primary new capability. Without it working correctly for a fresh project, the feature has no value.
|
|
44
|
+
|
|
45
|
+
**Independent Test**: Run `init --project-file` in a directory with no existing project config, then confirm that `.superposition.yml` is created at the repo root and reflects the chosen stack and overlays.
|
|
46
|
+
|
|
47
|
+
**Acceptance Scenarios**:
|
|
48
|
+
|
|
49
|
+
1. **Given** a repository with no project config file, **When** the user runs `init --project-file`, **Then** `.superposition.yml` is created at the repository root with the selected stack, base image, overlays, and other init options.
|
|
50
|
+
2. **Given** a repository with an existing `.superposition.yml`, **When** the user runs `init --project-file`, **Then** the existing file is updated (not a new file created) to reflect the newly selected configuration.
|
|
51
|
+
3. **Given** the project config write fails (e.g., permission error), **When** `init --project-file` is run, **Then** the devcontainer generation still completes successfully and a clear error message is shown for the project-file failure only.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
### User Story 2 - Update existing project config (Priority: P2)
|
|
56
|
+
|
|
57
|
+
A developer has an existing `superposition.yml` and wants to update it to reflect a changed overlay selection after re-running `init`.
|
|
58
|
+
|
|
59
|
+
**Why this priority**: Round-trip consistency (init → project config → regen) is the main value of the project-config workflow.
|
|
60
|
+
|
|
61
|
+
**Independent Test**: Create a `superposition.yml`, run `init --project-file` with different overlays, and confirm that the file is updated rather than a second file being created.
|
|
62
|
+
|
|
63
|
+
**Acceptance Scenarios**:
|
|
64
|
+
|
|
65
|
+
1. **Given** a repository with exactly one supported project config file, **When** the user runs `init --project-file` with new overlay selections, **Then** only that existing file is updated and no second project config is created.
|
|
66
|
+
2. **Given** two supported project config files exist simultaneously, **When** the user runs `init --project-file`, **Then** the command prints an error explaining that only one project config file should exist and does not proceed with the write.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Feature Specification: Target-Aware Generation
|
|
2
|
+
|
|
3
|
+
**Feature Branch**: `copilot/feat-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
|
+
## Review & Approval _(mandatory before implementation)_
|
|
9
|
+
|
|
10
|
+
- **Spec Path**: `docs/specs/007-target-aware-generation/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)_
|
|
16
|
+
|
|
17
|
+
### User Story 1 — Generate codespaces artifacts (Priority: P1)
|
|
18
|
+
|
|
19
|
+
A user generates with `--target codespaces` and expects to receive Codespaces-specific files and
|
|
20
|
+
guidance alongside the normal devcontainer output.
|
|
21
|
+
|
|
22
|
+
**Acceptance:**
|
|
23
|
+
|
|
24
|
+
1. `--target codespaces` → `devcontainer.json` extended with `hostRequirements`, `CODESPACES.md` written to `.devcontainer/`.
|
|
25
|
+
2. `--target local` or no `--target` → no `CODESPACES.md`, no `hostRequirements` in devcontainer.
|
|
26
|
+
|
|
27
|
+
### User Story 2 — Generate gitpod artifacts (Priority: P1)
|
|
28
|
+
|
|
29
|
+
A user generates with `--target gitpod` and expects a `.gitpod.yml` in the project root and
|
|
30
|
+
setup guidance inside `.devcontainer/`.
|
|
31
|
+
|
|
32
|
+
**Acceptance:**
|
|
33
|
+
|
|
34
|
+
1. `--target gitpod` → `.gitpod.yml` at project root with tasks and port exposures from selected overlays; `GITPOD.md` written to `.devcontainer/`.
|
|
35
|
+
2. `--target local` → no `.gitpod.yml`, no `GITPOD.md`.
|
|
36
|
+
|
|
37
|
+
### User Story 3 — Generate devpod artifacts (Priority: P1)
|
|
38
|
+
|
|
39
|
+
A user generates with `--target devpod` and expects a `devpod.yaml` at the project root and
|
|
40
|
+
setup guidance inside `.devcontainer/`.
|
|
41
|
+
|
|
42
|
+
**Acceptance:**
|
|
43
|
+
|
|
44
|
+
1. `--target devpod` → `devpod.yaml` at project root; `DEVPOD.md` written to `.devcontainer/`.
|
|
45
|
+
2. `--target local` → no `devpod.yaml`, no `DEVPOD.md`.
|
|
46
|
+
|
|
47
|
+
### User Story 4 — Local generation unchanged (Priority: P1)
|
|
48
|
+
|
|
49
|
+
When a user generates without specifying a target, or with `--target local`, the output must
|
|
50
|
+
not contain any non-local artifacts.
|
|
51
|
+
|
|
52
|
+
**Acceptance:**
|
|
53
|
+
|
|
54
|
+
1. No `--target` flag → output identical to current behavior; no new files written.
|
|
55
|
+
2. `--target local` (explicit) → same output as omitting `--target`.
|
|
56
|
+
|
|
57
|
+
### User Story 5 — Regeneration from manifest with target (Priority: P2)
|
|
58
|
+
|
|
59
|
+
A user regenerates from an existing `superposition.json` that includes `"target": "gitpod"` and
|
|
60
|
+
expects the same Gitpod-specific artifacts without being prompted again.
|
|
61
|
+
|
|
62
|
+
**Acceptance:**
|
|
63
|
+
|
|
64
|
+
1. Manifest with `target: gitpod` → regen produces `.gitpod.yml` and `GITPOD.md`.
|
|
65
|
+
2. Manifest with no `target` or `target: local` → regen produces no target-specific artifacts.
|
|
66
|
+
|
|
67
|
+
### User Story 6 — Target switching cleans up stale artifacts (Priority: P2)
|
|
68
|
+
|
|
69
|
+
A user regenerates with a different `--target` value and expects the previous target's
|
|
70
|
+
project-root artifacts to be removed.
|
|
71
|
+
|
|
72
|
+
**Acceptance:**
|
|
73
|
+
|
|
74
|
+
1. Previous run was `--target gitpod` (`.gitpod.yml` exists); regeneration with `--target codespaces` → `.gitpod.yml` removed, `CODESPACES.md` written.
|
|
75
|
+
2. Previous run was `--target devpod`; regeneration with `--target local` → `devpod.yaml` removed.
|
|
76
|
+
|
|
77
|
+
## Technical Design
|
|
78
|
+
|
|
79
|
+
### `TargetRule` interface
|
|
80
|
+
|
|
81
|
+
A `TargetRule` encapsulates everything about generating artifacts for one deployment target:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
interface TargetRule {
|
|
85
|
+
target: DeploymentTarget;
|
|
86
|
+
/** Extra fields merged into devcontainer.json */
|
|
87
|
+
devcontainerPatch(context: TargetRuleContext): Partial<DevContainer>;
|
|
88
|
+
/** Files to write; keys are relative to outputPath, '../<name>' writes to project root */
|
|
89
|
+
generateFiles(context: TargetRuleContext): Map<string, string>;
|
|
90
|
+
/** All relative paths owned by this rule (for stale-cleanup on target switch) */
|
|
91
|
+
ownedFiles(): string[];
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Per-target rules
|
|
96
|
+
|
|
97
|
+
| Target | devcontainer.json change | Files in `.devcontainer/` | Files at project root |
|
|
98
|
+
| ------------ | ------------------------ | ------------------------- | --------------------- |
|
|
99
|
+
| `local` | none | none | none |
|
|
100
|
+
| `codespaces` | `hostRequirements` | `CODESPACES.md` | none |
|
|
101
|
+
| `gitpod` | none | `GITPOD.md` | `.gitpod.yml` |
|
|
102
|
+
| `devpod` | none | `DEVPOD.md` | `devpod.yaml` |
|
|
103
|
+
|
|
104
|
+
### `SuperpositionManifest` update
|
|
105
|
+
|
|
106
|
+
Add `target?: DeploymentTarget` so regeneration reproduces the correct artifacts without
|
|
107
|
+
re-prompting.
|
|
108
|
+
|
|
109
|
+
### Stale-artifact cleanup
|
|
110
|
+
|
|
111
|
+
On each generation, before writing new target artifacts:
|
|
112
|
+
|
|
113
|
+
1. Read existing `superposition.json` from `outputPath` (if it exists).
|
|
114
|
+
2. If `manifest.target !== answers.target`, identify previous target's owned project-root
|
|
115
|
+
files (e.g., `.gitpod.yml`) and remove them from the project root.
|
|
116
|
+
|
|
117
|
+
The `.devcontainer/`-local files are already handled by `cleanupStaleFiles` via `FileRegistry`.
|
|
118
|
+
|
|
119
|
+
## Functional Requirements (from issue)
|
|
120
|
+
|
|
121
|
+
- **FR-001**: Target is a real generation input that changes produced artifacts.
|
|
122
|
+
- **FR-002**: `codespaces`, `gitpod`, `devpod` produce target-specific workspace artifacts.
|
|
123
|
+
- **FR-003**: `local` (explicit or default) produces no additional artifacts.
|
|
124
|
+
- **FR-009**: Regeneration from manifest reproduces target-aware output automatically.
|
|
125
|
+
- **FR-010**: Target switch between runs removes stale artifacts from the previous target.
|
|
126
|
+
- **FR-011**: Backward compatible — manifests without `target` or with `target: local` unchanged.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
Feature Branch: copilot/make-superposition-yml-canonical-input
|
|
3
|
+
Created: 2026-03-26
|
|
4
|
+
Status: Implementing
|
|
5
|
+
Input: GitHub issue #134
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Spec: Make superposition.yml the Canonical Input
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
Make `superposition.yml` (the project config file) the required, canonical input for all
|
|
13
|
+
generation and regeneration flows. `superposition.json` (the manifest) becomes an output-only
|
|
14
|
+
artifact — a generated receipt, not an input source.
|
|
15
|
+
|
|
16
|
+
## Motivation
|
|
17
|
+
|
|
18
|
+
Three entry points currently disagree on which file is authoritative, creating user confusion
|
|
19
|
+
and dead code paths. The newest code path (`generate`) already writes `superposition.yml`
|
|
20
|
+
first. This spec promotes that pattern to all entry points.
|
|
21
|
+
|
|
22
|
+
## Behavioral Changes
|
|
23
|
+
|
|
24
|
+
### `init` — Always writes `superposition.yml`
|
|
25
|
+
|
|
26
|
+
- Remove `--project-file` flag; writing the project config is now the default.
|
|
27
|
+
- Add `--no-scaffold` flag to skip generating `.devcontainer/` (for project-file-only runs).
|
|
28
|
+
- Scaffold (`.devcontainer/` generation) remains the default for backward compatibility.
|
|
29
|
+
- The project file is written before scaffolding; a scaffold failure does not lose the config.
|
|
30
|
+
|
|
31
|
+
### `regen` — Reads `superposition.yml` only
|
|
32
|
+
|
|
33
|
+
- Default input: the project config file auto-discovered in the repository root.
|
|
34
|
+
- `--from-manifest <path>` is retained as a **deprecated hidden flag** that emits a warning
|
|
35
|
+
pointing toward `cs migrate`. Existing CI scripts that rely on it will still work but
|
|
36
|
+
receive a deprecation notice.
|
|
37
|
+
- If no project file exists and `superposition.json` is present: error with actionable
|
|
38
|
+
migration guidance: `Run 'cs migrate' to create a project file from your existing manifest.`
|
|
39
|
+
- If neither file exists: error with creation guidance.
|
|
40
|
+
|
|
41
|
+
### `superposition.json` — Output only
|
|
42
|
+
|
|
43
|
+
- Still written by `composeDevContainer` / `generateManifestOnly` as before.
|
|
44
|
+
- No longer read as a generation input in the standard flow.
|
|
45
|
+
- Still read by `doctor` for diagnostics and drift detection.
|
|
46
|
+
|
|
47
|
+
## New Commands
|
|
48
|
+
|
|
49
|
+
### `cs migrate`
|
|
50
|
+
|
|
51
|
+
One-time migration from manifest-only repositories:
|
|
52
|
+
|
|
53
|
+
1. Discovers or accepts `--from-manifest <path>` to locate `superposition.json`.
|
|
54
|
+
2. Loads and validates the manifest (with auto-migration for old versions).
|
|
55
|
+
3. Converts manifest to `ProjectConfigSelection` via the existing
|
|
56
|
+
`buildAnswersFromManifest → mergeAnswers → buildProjectConfigSelectionFromAnswers` pipeline.
|
|
57
|
+
4. Discovers the output path for the project file (uses existing file if present, otherwise
|
|
58
|
+
defaults to `.superposition.yml`); `--force` to overwrite.
|
|
59
|
+
5. Writes the project config YAML.
|
|
60
|
+
6. Prints a success message with next-step guidance (`regen` to regenerate).
|
|
61
|
+
|
|
62
|
+
## `doctor` Drift Detection
|
|
63
|
+
|
|
64
|
+
Once the project file is canonical, `doctor` can compare the two files:
|
|
65
|
+
|
|
66
|
+
- Load project file overlays (via `loadProjectConfig`).
|
|
67
|
+
- Load last-generated manifest overlays (via existing manifest loading).
|
|
68
|
+
- Report a new `project-file-drift` finding when the overlay sets differ.
|
|
69
|
+
- Suggest `regen` to reconcile.
|
|
70
|
+
|
|
71
|
+
## Migration Considerations
|
|
72
|
+
|
|
73
|
+
| Repo state | Impact | Action |
|
|
74
|
+
| ----------------------------- | --------------------------------- | -------------------------------- |
|
|
75
|
+
| Has `superposition.yml` only | None — already correct | — |
|
|
76
|
+
| Has `superposition.json` only | `regen` errors | Run `cs migrate` once |
|
|
77
|
+
| Has both (consistent) | None — regen prefers project file | — |
|
|
78
|
+
| CI using `--from-manifest` | Warning on each run | Switch to `cs migrate` + `regen` |
|
|
79
|
+
|
|
80
|
+
## Review & Approval Gate
|
|
81
|
+
|
|
82
|
+
Implementation proceeds with this spec committed. No further approval required for the
|
|
83
|
+
behavioral changes listed above.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Feature Specification: Unified Project-Level Environment Variables
|
|
2
|
+
|
|
3
|
+
**Feature Branch**: `codex/project-env`
|
|
4
|
+
**Created**: 2026-03-29
|
|
5
|
+
**Status**: Implementing
|
|
6
|
+
**Input**: User request
|
|
7
|
+
|
|
8
|
+
## Review & Approval _(mandatory before implementation)_
|
|
9
|
+
|
|
10
|
+
- **Spec Path**: `docs/specs/009-project-env/spec.md`
|
|
11
|
+
- **Commit Status**: Committed
|
|
12
|
+
- **Review Status**: Pending
|
|
13
|
+
- **Implementation Gate**: No implementation code may begin until this spec is committed and reviewed.
|
|
14
|
+
|
|
15
|
+
## User Scenarios & Testing _(mandatory)_
|
|
16
|
+
|
|
17
|
+
### User Story 1 — Define environment variables once for plain stack (Priority: P1)
|
|
18
|
+
|
|
19
|
+
A developer adds an `env:` block to `superposition.yml` on a `plain` stack and expects the
|
|
20
|
+
variables to appear in `devcontainer.json → remoteEnv` after regeneration.
|
|
21
|
+
|
|
22
|
+
**Why this priority**: The most common use case is a plain-stack project needing a handful of
|
|
23
|
+
environment variables visible inside the devcontainer without manually editing JSON files.
|
|
24
|
+
|
|
25
|
+
**Independent Test**: Create a `superposition.yml` with `stack: plain` and `env: {APP_NAME: my-app}`,
|
|
26
|
+
run `regen`, and confirm that `devcontainer.json` contains `"remoteEnv": {"APP_NAME": "my-app"}`.
|
|
27
|
+
|
|
28
|
+
**Acceptance Scenarios**:
|
|
29
|
+
|
|
30
|
+
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`.
|
|
31
|
+
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.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
### User Story 2 — Define environment variables once for compose stack (Priority: P1)
|
|
36
|
+
|
|
37
|
+
A developer adds an `env:` block to `superposition.yml` on a `compose` stack and expects the
|
|
38
|
+
variables to appear in `docker-compose.yml → services.devcontainer.environment` after regeneration.
|
|
39
|
+
|
|
40
|
+
**Why this priority**: Compose-stack users currently must split env configuration across
|
|
41
|
+
`customizations.devcontainerPatch.remoteEnv` and `customizations.dockerComposePatch`, which is
|
|
42
|
+
error-prone and hard to discover.
|
|
43
|
+
|
|
44
|
+
**Independent Test**: Create a `superposition.yml` with `stack: compose` and
|
|
45
|
+
`env: {DB_HOST: postgres}`, run `regen`, and confirm the variable appears under
|
|
46
|
+
`services.devcontainer.environment` in the generated `docker-compose.yml`.
|
|
47
|
+
|
|
48
|
+
**Acceptance Scenarios**:
|
|
49
|
+
|
|
50
|
+
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`.
|
|
51
|
+
2. **Given** `target: composeEnv` is specified, **When** generation runs with `stack: plain`, **Then** generation errors with a clear message about compose-only targets.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
### User Story 3 — Explicit target overrides auto-routing (Priority: P2)
|
|
56
|
+
|
|
57
|
+
A developer uses `target: remoteEnv` on a compose-stack project to force a variable into
|
|
58
|
+
`devcontainer.json` instead of `docker-compose.yml`.
|
|
59
|
+
|
|
60
|
+
**Why this priority**: Power users occasionally need fine-grained control over where a variable
|
|
61
|
+
lands, especially for VS Code-specific settings that must be in `remoteEnv`.
|
|
62
|
+
|
|
63
|
+
**Independent Test**: Set `target: remoteEnv` on a variable in a compose-stack project, run
|
|
64
|
+
`regen`, and confirm the variable is in `devcontainer.json → remoteEnv` (not in
|
|
65
|
+
`docker-compose.yml → services.devcontainer.environment`).
|
|
66
|
+
|
|
67
|
+
**Acceptance Scenarios**:
|
|
68
|
+
|
|
69
|
+
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.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Overview
|
|
74
|
+
|
|
75
|
+
Add a first-class `env` field to `superposition.yml` so a project can define
|
|
76
|
+
environment variables once and have them land in the correct generated output:
|
|
77
|
+
|
|
78
|
+
- `remoteEnv` for `plain` stacks
|
|
79
|
+
- `services.devcontainer.environment` in `docker-compose.yml` for `compose` stacks
|
|
80
|
+
|
|
81
|
+
This removes the need to split simple container environment variables across
|
|
82
|
+
`customizations.devcontainerPatch.remoteEnv` and
|
|
83
|
+
`customizations.dockerComposePatch`.
|
|
84
|
+
|
|
85
|
+
## Project File Shape
|
|
86
|
+
|
|
87
|
+
```yaml
|
|
88
|
+
env:
|
|
89
|
+
APP_NAME: my-app
|
|
90
|
+
API_BASE_URL:
|
|
91
|
+
value: ${API_BASE_URL:-http://localhost:3000}
|
|
92
|
+
target: auto
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Rules:
|
|
96
|
+
|
|
97
|
+
- `env` is a map keyed by variable name.
|
|
98
|
+
- A value may be:
|
|
99
|
+
- a string shorthand, equivalent to `{ value: "<string>", target: auto }`
|
|
100
|
+
- an object with:
|
|
101
|
+
- `value: string` required
|
|
102
|
+
- `target: auto | remoteEnv | composeEnv` optional, default `auto`
|
|
103
|
+
|
|
104
|
+
## Generation Behavior
|
|
105
|
+
|
|
106
|
+
### `target: auto`
|
|
107
|
+
|
|
108
|
+
- `plain` stack: write the variable to `devcontainer.json -> remoteEnv`
|
|
109
|
+
- `compose` stack: write the variable to
|
|
110
|
+
`docker-compose.yml -> services.devcontainer.environment`
|
|
111
|
+
|
|
112
|
+
### Explicit targets
|
|
113
|
+
|
|
114
|
+
- `remoteEnv`: always write to `devcontainer.json -> remoteEnv`
|
|
115
|
+
- `composeEnv`: write to `docker-compose.yml -> services.devcontainer.environment`
|
|
116
|
+
and error on non-compose stacks
|
|
117
|
+
|
|
118
|
+
### Precedence
|
|
119
|
+
|
|
120
|
+
- Project-level `env` is applied before `customizations.devcontainerPatch` and
|
|
121
|
+
`customizations.dockerComposePatch`.
|
|
122
|
+
- Custom patch files remain the escape hatch and may override project-level env.
|
|
123
|
+
|
|
124
|
+
## Root `.env` Expansion Bridge
|
|
125
|
+
|
|
126
|
+
When a compose-targeted project env value references `${NAME}` or
|
|
127
|
+
`${NAME:-default}`, generation should preserve that expression in
|
|
128
|
+
`docker-compose.yml` and also mirror matching keys from the project root `.env`
|
|
129
|
+
into `.devcontainer/.env`.
|
|
130
|
+
|
|
131
|
+
This allows:
|
|
132
|
+
|
|
133
|
+
1. the repository root `.env` to remain the human-edited source of truth
|
|
134
|
+
2. Docker Compose to resolve variables from `.devcontainer/.env`
|
|
135
|
+
3. generated `docker-compose.yml` to avoid embedding resolved secret values
|
|
136
|
+
|
|
137
|
+
Bridge rules:
|
|
138
|
+
|
|
139
|
+
- only referenced variable names are copied
|
|
140
|
+
- existing unrelated entries in `.devcontainer/.env` are preserved
|
|
141
|
+
- missing root variables are not invented; Docker Compose defaults still work
|
|
142
|
+
|
|
143
|
+
## Non-Goals
|
|
144
|
+
|
|
145
|
+
- No new syntax for targeting arbitrary non-devcontainer services
|
|
146
|
+
- No replacement for advanced compose patches; those remain under
|
|
147
|
+
`customizations.dockerComposePatch`
|