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.
- package/README.md +24 -15
- package/dist/scripts/init.js +1 -1537
- 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.js +1 -1
- package/dist/tool/commands/adopt.js.map +1 -1
- package/dist/tool/commands/doctor.d.ts +1 -0
- package/dist/tool/commands/doctor.d.ts.map +1 -1
- package/dist/tool/commands/doctor.js +1510 -78
- 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 +9 -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 +6 -4
- package/dist/tool/questionnaire/composer.d.ts.map +1 -1
- package/dist/tool/questionnaire/composer.js +778 -45
- 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 +165 -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 +582 -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 +24 -0
- package/dist/tool/schema/overlay-loader.js.map +1 -1
- package/dist/tool/schema/project-config.d.ts +13 -1
- package/dist/tool/schema/project-config.d.ts.map +1 -1
- package/dist/tool/schema/project-config.js +188 -10
- 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 +42 -3
- package/dist/tool/schema/types.d.ts.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/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 +92 -14
- package/docs/overlays.md +231 -135
- package/docs/specs/001-verbose-plan-graph/spec.md +5 -12
- package/docs/specs/002-superposition-config-file/spec.md +5 -12
- package/docs/specs/003-mkdocs2-overlay/spec.md +2 -9
- package/docs/specs/004-doctor-fix/spec.md +1 -8
- package/docs/specs/005-cuda-overlay/spec.md +2 -9
- package/docs/specs/006-rocm-overlay/spec.md +3 -10
- package/docs/specs/007-target-aware-generation/spec.md +119 -0
- package/docs/specs/008-project-file-canonical/spec.md +82 -0
- package/docs/specs/009-project-env/spec.md +140 -0
- package/docs/specs/010-compose-env-materialization/spec.md +123 -0
- package/docs/specs/011-overlay-parameters/spec.md +228 -0
- package/docs/specs/012-ollama-cli-overlay/spec.md +47 -0
- package/docs/specs/013-doctor-dependency-check/spec.md +250 -0
- package/docs/specs/014-doctor-compose-port-cross-validation/spec.md +276 -0
- package/docs/specs/015-doctor-env-example-drift/spec.md +248 -0
- package/docs/specs/016-doctor-reproducibility-check/spec.md +276 -0
- package/docs/specs/017-doctor-dry-run/spec.md +276 -0
- package/docs/specs/018-init-project-file/spec.md +59 -0
- package/docs/specs/taxonomy.md +186 -0
- package/overlays/.presets/full-observability.yml +113 -0
- package/overlays/.presets/k8s-dev.yml +174 -0
- package/overlays/.presets/local-llm.yml +105 -0
- package/overlays/.presets/vector-ai.yml +150 -0
- package/overlays/.shared/README.md +27 -2
- package/overlays/.shared/compose/nvidia-gpu-devcontainer.yml +22 -0
- package/overlays/.shared/vscode/js-ts-settings.json +19 -0
- package/overlays/.shared/vscode/markdown-extensions.json +8 -0
- package/overlays/alertmanager/devcontainer.patch.json +0 -1
- package/overlays/alertmanager/docker-compose.yml +8 -0
- package/overlays/alertmanager/overlay.yml +1 -0
- package/overlays/amp/devcontainer.patch.json +4 -1
- package/overlays/bun/devcontainer.patch.json +1 -10
- package/overlays/bun/overlay.yml +8 -1
- package/overlays/claude-code/devcontainer.patch.json +6 -1
- package/overlays/codex/devcontainer.patch.json +5 -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 +40 -0
- package/overlays/comfyui/overlay.yml +24 -0
- package/overlays/comfyui/setup.sh +36 -0
- package/overlays/comfyui/verify.sh +103 -0
- package/overlays/commitlint/devcontainer.patch.json +1 -6
- package/overlays/docker-sock/overlay.yml +1 -0
- package/overlays/dotnet/overlay.yml +4 -1
- package/overlays/fuseki/.env.example +5 -0
- package/overlays/fuseki/README.md +173 -0
- package/overlays/fuseki/devcontainer.patch.json +18 -0
- package/overlays/fuseki/docker-compose.yml +29 -0
- package/overlays/fuseki/overlay.yml +42 -0
- package/overlays/fuseki/verify.sh +58 -0
- package/overlays/gemini-cli/devcontainer.patch.json +4 -1
- package/overlays/go/overlay.yml +6 -1
- package/overlays/grafana/devcontainer.patch.json +0 -1
- package/overlays/grafana/docker-compose.yml +8 -2
- package/overlays/grafana/overlay.yml +6 -1
- package/overlays/jaeger/.env.example +11 -0
- package/overlays/jaeger/README.md +33 -4
- package/overlays/jaeger/devcontainer.patch.json +9 -1
- package/overlays/jaeger/docker-compose.yml +17 -0
- package/overlays/jaeger/overlay.yml +1 -12
- package/overlays/java/overlay.yml +6 -1
- package/overlays/jupyter/docker-compose.yml +1 -0
- package/overlays/jupyter/overlay.yml +1 -0
- 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/devcontainer.patch.json +0 -1
- package/overlays/keycloak/docker-compose.yml +1 -0
- package/overlays/keycloak/overlay.yml +15 -0
- package/overlays/localstack/docker-compose.yml +1 -0
- package/overlays/localstack/overlay.yml +19 -1
- package/overlays/loki/devcontainer.patch.json +0 -1
- package/overlays/loki/docker-compose.yml +8 -0
- package/overlays/loki/overlay.yml +1 -0
- package/overlays/mailpit/docker-compose.yml +1 -0
- package/overlays/mailpit/overlay.yml +1 -0
- package/overlays/minio/devcontainer.patch.json +1 -1
- package/overlays/minio/docker-compose.yml +1 -0
- package/overlays/minio/overlay.yml +23 -2
- package/overlays/mkdocs/devcontainer.patch.json +1 -5
- package/overlays/mkdocs/overlay.yml +3 -1
- package/overlays/mkdocs2/devcontainer.patch.json +1 -5
- package/overlays/mkdocs2/overlay.yml +2 -0
- package/overlays/mongodb/docker-compose.yml +2 -0
- package/overlays/mongodb/overlay.yml +26 -2
- package/overlays/mysql/docker-compose.yml +2 -0
- package/overlays/mysql/overlay.yml +36 -2
- package/overlays/nats/docker-compose.yml +1 -0
- package/overlays/nats/overlay.yml +18 -2
- package/overlays/nodejs/devcontainer.patch.json +1 -12
- package/overlays/nodejs/overlay.yml +8 -1
- package/overlays/ollama/.env.example +14 -0
- package/overlays/ollama/README.md +326 -0
- package/overlays/ollama/devcontainer.patch.json +14 -0
- package/overlays/ollama/docker-compose.yml +25 -0
- package/overlays/ollama/overlay.yml +27 -0
- package/overlays/ollama/verify.sh +76 -0
- package/overlays/ollama-cli/README.md +90 -0
- package/overlays/ollama-cli/devcontainer.patch.json +3 -0
- package/overlays/ollama-cli/overlay.yml +19 -0
- package/overlays/ollama-cli/setup.sh +103 -0
- package/overlays/ollama-cli/verify.sh +49 -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 +24 -0
- package/overlays/open-webui/overlay.yml +45 -0
- package/overlays/opencode/devcontainer.patch.json +4 -1
- package/overlays/otel-collector/README.md +4 -0
- package/overlays/otel-collector/devcontainer.patch.json +4 -1
- package/overlays/otel-collector/docker-compose.yml +8 -4
- package/overlays/otel-collector/overlay.yml +1 -0
- package/overlays/otel-demo-nodejs/devcontainer.patch.json +0 -1
- package/overlays/otel-demo-nodejs/docker-compose.yml +1 -0
- package/overlays/otel-demo-nodejs/overlay.yml +9 -1
- package/overlays/otel-demo-python/devcontainer.patch.json +0 -1
- package/overlays/otel-demo-python/docker-compose.yml +1 -0
- package/overlays/otel-demo-python/overlay.yml +6 -1
- package/overlays/pandoc/README.md +10 -0
- package/overlays/pandoc/devcontainer.patch.json +0 -5
- package/overlays/pandoc/overlay.yml +2 -0
- package/overlays/pandoc/setup.sh +10 -0
- package/overlays/pgvector/.env.example +6 -0
- package/overlays/pgvector/README.md +215 -0
- package/overlays/pgvector/devcontainer.patch.json +29 -0
- package/overlays/pgvector/docker-compose.yml +33 -0
- package/overlays/pgvector/overlay.yml +47 -0
- package/overlays/playwright/devcontainer.patch.json +0 -5
- package/overlays/playwright/overlay.yml +2 -1
- package/overlays/postgres/.env.example +5 -5
- package/overlays/postgres/devcontainer.patch.json +4 -4
- package/overlays/postgres/docker-compose.yml +11 -6
- package/overlays/postgres/overlay.yml +23 -2
- package/overlays/pre-commit/devcontainer.patch.json +1 -7
- package/overlays/prometheus/devcontainer.patch.json +0 -1
- package/overlays/prometheus/docker-compose.yml +8 -0
- package/overlays/prometheus/overlay.yml +1 -0
- package/overlays/promtail/devcontainer.patch.json +1 -2
- package/overlays/promtail/docker-compose.yml +8 -0
- package/overlays/promtail/overlay.yml +1 -0
- 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 +26 -0
- package/overlays/qdrant/overlay.yml +44 -0
- package/overlays/rabbitmq/docker-compose.yml +1 -0
- package/overlays/rabbitmq/overlay.yml +25 -2
- package/overlays/redis/docker-compose.yml +7 -0
- package/overlays/redis/overlay.yml +15 -1
- package/overlays/redpanda/docker-compose.yml +1 -0
- package/overlays/redpanda/overlay.yml +15 -3
- package/overlays/rocm/overlay.yml +2 -1
- package/overlays/rust/overlay.yml +3 -1
- 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/sqlserver/docker-compose.yml +1 -0
- package/overlays/sqlserver/overlay.yml +17 -0
- package/overlays/tempo/devcontainer.patch.json +0 -1
- package/overlays/tempo/docker-compose.yml +8 -0
- package/overlays/tempo/overlay.yml +1 -0
- package/overlays/windsurf-cli/devcontainer.patch.json +4 -1
- package/package.json +3 -2
- package/tool/schema/config.schema.json +31 -1
- package/tool/schema/overlay-manifest.schema.json +33 -0
- package/overlays/.shared/otel/otel-base-config.yaml +0 -30
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Feature Specification: Overlay Parameters with Safe Substitution
|
|
2
|
+
|
|
3
|
+
**Spec ID**: `011-overlay-parameters`
|
|
4
|
+
**Created**: 2026-03-30
|
|
5
|
+
**Status**: Final
|
|
6
|
+
**Input**: Issue — Introduce overlay parameters with safe, namespaced substitution — no conflicts with Docker/shell/VS Code
|
|
7
|
+
|
|
8
|
+
## Summary
|
|
9
|
+
|
|
10
|
+
Add first-class **parameters** to overlays so users can configure environment-specific values
|
|
11
|
+
(credentials, database names, ports, paths) without forking overlays or hand-editing generated
|
|
12
|
+
files.
|
|
13
|
+
|
|
14
|
+
Parameters use the `{{cs.PARAM_NAME}}` substitution syntax, which does not collide with Docker
|
|
15
|
+
Compose (`${VAR}`), shell (`$VAR`, `${VAR}`), VS Code (`${localWorkspaceFolder}`), or GitHub
|
|
16
|
+
Actions (`${{ }}`).
|
|
17
|
+
|
|
18
|
+
This is **parameter substitution only** — no loops, no conditionals, no embedded logic.
|
|
19
|
+
If `string.replace()` can't do it, it doesn't belong here.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Design
|
|
24
|
+
|
|
25
|
+
### Syntax
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
{{cs.PARAM_NAME}}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- **Safe**: does not collide with `${VAR}` (Docker/shell), `${env:VAR}` (VS Code), or `${{ }}` (GitHub Actions)
|
|
32
|
+
- **Consistent**: extends the existing `{{parameters.<key>.id}}` preset convention
|
|
33
|
+
- **Explicit**: clearly owned by container-superposition
|
|
34
|
+
- **Simple**: resolved by a single `string.replace()` regex, no parser needed
|
|
35
|
+
|
|
36
|
+
### Overlay parameter declarations (`overlay.yml`)
|
|
37
|
+
|
|
38
|
+
Overlays declare parameters in `overlay.yml`:
|
|
39
|
+
|
|
40
|
+
```yaml
|
|
41
|
+
id: postgres
|
|
42
|
+
name: PostgreSQL
|
|
43
|
+
category: database
|
|
44
|
+
parameters:
|
|
45
|
+
POSTGRES_DB:
|
|
46
|
+
description: Database name
|
|
47
|
+
default: app
|
|
48
|
+
POSTGRES_USER:
|
|
49
|
+
description: Database user
|
|
50
|
+
default: postgres
|
|
51
|
+
POSTGRES_PASSWORD:
|
|
52
|
+
description: Database password
|
|
53
|
+
default: postgres
|
|
54
|
+
sensitive: true
|
|
55
|
+
POSTGRES_PORT:
|
|
56
|
+
description: Host-mapped port
|
|
57
|
+
default: '5432'
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Fields:
|
|
61
|
+
|
|
62
|
+
- `description` (required) — human-readable explanation shown in interactive prompts
|
|
63
|
+
- `default` (optional) — default value; absence marks the parameter as _required_
|
|
64
|
+
- `sensitive` (optional, boolean) — indicates secrets; hidden in interactive prompts and redacted from plan output
|
|
65
|
+
|
|
66
|
+
### Usage in overlay files
|
|
67
|
+
|
|
68
|
+
Overlay patches and compose files reference parameters using `{{cs.PARAM_NAME}}`:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"remoteEnv": {
|
|
73
|
+
"DATABASE_URL": "postgres://{{cs.POSTGRES_USER}}:{{cs.POSTGRES_PASSWORD}}@postgres:5432/{{cs.POSTGRES_DB}}"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
# docker-compose.yml — generation-time substitution coexists with Docker runtime substitution
|
|
80
|
+
services:
|
|
81
|
+
postgres:
|
|
82
|
+
environment:
|
|
83
|
+
POSTGRES_DB: '{{cs.POSTGRES_DB}}'
|
|
84
|
+
POSTGRES_USER: '{{cs.POSTGRES_USER}}'
|
|
85
|
+
POSTGRES_PASSWORD: '{{cs.POSTGRES_PASSWORD}}'
|
|
86
|
+
ports:
|
|
87
|
+
- '${POSTGRES_PORT:-{{cs.POSTGRES_PORT}}}:5432'
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Parameters in `superposition.yml`
|
|
91
|
+
|
|
92
|
+
```yaml
|
|
93
|
+
overlays:
|
|
94
|
+
- postgres
|
|
95
|
+
- redis
|
|
96
|
+
|
|
97
|
+
parameters:
|
|
98
|
+
POSTGRES_DB: myapp
|
|
99
|
+
POSTGRES_USER: veggerby
|
|
100
|
+
REDIS_PORT: '6380'
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Resolution order (highest wins)
|
|
104
|
+
|
|
105
|
+
1. CLI overrides (`--param POSTGRES_DB=foo`)
|
|
106
|
+
2. Project file (`superposition.yml` `parameters:` section)
|
|
107
|
+
3. Overlay defaults (`overlay.yml` `parameters[KEY].default`)
|
|
108
|
+
|
|
109
|
+
### Validation rules
|
|
110
|
+
|
|
111
|
+
| Condition | Behaviour |
|
|
112
|
+
| ---------------------------------------------------------- | ------------------------------------- |
|
|
113
|
+
| Missing required parameter (no default, no value supplied) | **Hard error** before generation |
|
|
114
|
+
| Unknown parameter (not declared by any selected overlay) | **Warning** (proceed) |
|
|
115
|
+
| Unresolved `{{cs.*}}` in final output | **Hard error** (catch-all safety net) |
|
|
116
|
+
|
|
117
|
+
### Pass-through guarantee
|
|
118
|
+
|
|
119
|
+
The substitution engine MUST NOT touch:
|
|
120
|
+
|
|
121
|
+
- Docker Compose expressions: `${VAR}`, `${VAR:-default}`, `$VAR`
|
|
122
|
+
- VS Code/devcontainer variables: `${localWorkspaceFolder}`, `${containerWorkspaceFolder}`, `${env:VAR}`
|
|
123
|
+
- GitHub Actions expressions: `${{ github.* }}`
|
|
124
|
+
- Shell variables in scripts: `$FOO`, `${FOO}`, `${FOO:-default}`
|
|
125
|
+
|
|
126
|
+
Only tokens matching exactly `{{cs.[A-Z0-9_]+}}` are substituted.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Implementation Scope
|
|
131
|
+
|
|
132
|
+
### Types (`tool/schema/types.ts`)
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
export interface OverlayParameterDefinition {
|
|
136
|
+
description: string;
|
|
137
|
+
default?: string;
|
|
138
|
+
sensitive?: boolean;
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Add to `OverlayMetadata`:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
parameters?: Record<string, OverlayParameterDefinition>;
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Add to `ProjectConfigSelection`:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
parameters?: Record<string, string>;
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Add to `QuestionnaireAnswers`:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
overlayParameters?: Record<string, string>;
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Parameter engine (`tool/utils/parameters.ts`)
|
|
161
|
+
|
|
162
|
+
- `collectOverlayParameters(overlayIds, allOverlayDefs)` — collect all declared parameters from selected overlays with their defaults
|
|
163
|
+
- `resolveParameters(declared, supplied)` — apply resolution order, return resolved map and errors
|
|
164
|
+
- `substituteParameters(content, resolved)` — replace `{{cs.KEY}}` tokens in a string
|
|
165
|
+
- `validateFinalContent(content)` — error if any `{{cs.*}}` remain after substitution
|
|
166
|
+
|
|
167
|
+
### Composer (`tool/questionnaire/composer.ts`)
|
|
168
|
+
|
|
169
|
+
After all overlay files are read and before they are written to disk:
|
|
170
|
+
|
|
171
|
+
1. Collect parameter declarations from selected overlays
|
|
172
|
+
2. Merge with `answers.overlayParameters` values
|
|
173
|
+
3. Validate — error on missing required parameters
|
|
174
|
+
4. Apply substitution to all file content strings (devcontainer.json, docker-compose.yml, .env.example, scripts)
|
|
175
|
+
5. Validate — error on any unresolved `{{cs.*}}` tokens remaining in output
|
|
176
|
+
|
|
177
|
+
### Project config (`tool/schema/project-config.ts`)
|
|
178
|
+
|
|
179
|
+
Parse `parameters:` YAML map as `Record<string, string>` (string values only).
|
|
180
|
+
Propagate to `selection.parameters` → `answers.overlayParameters`.
|
|
181
|
+
|
|
182
|
+
### Init (`scripts/init.ts`)
|
|
183
|
+
|
|
184
|
+
When overlay declares parameters, interactive questionnaire prompts for values.
|
|
185
|
+
Sensitive parameters use masked input. Pre-filled with defaults.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Non-goals
|
|
190
|
+
|
|
191
|
+
- Conditional logic (`{{if ...}}`)
|
|
192
|
+
- Loops or iteration
|
|
193
|
+
- Programmable overlays or JS execution
|
|
194
|
+
- Dynamic file generation
|
|
195
|
+
- Templating engine integration (Handlebars, Jinja, EJS, etc.)
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## User Scenarios & Testing
|
|
200
|
+
|
|
201
|
+
### User Story 1 — Postgres with custom database name (P1)
|
|
202
|
+
|
|
203
|
+
A user scaffolds a compose stack with the postgres overlay and wants their database named `myapp`
|
|
204
|
+
instead of the default `devdb`.
|
|
205
|
+
|
|
206
|
+
**Acceptance scenarios**:
|
|
207
|
+
|
|
208
|
+
1. **Given** a `superposition.yml` with `parameters: { POSTGRES_DB: myapp }`, **When** generation runs, **Then** the generated `.devcontainer/docker-compose.yml` and `remoteEnv` in `devcontainer.json` reference `myapp` instead of `devdb`.
|
|
209
|
+
2. **Given** an overlay with a required parameter (no default), **When** generation is run without providing the parameter value, **Then** the tool exits with a clear error message before writing any files.
|
|
210
|
+
3. **Given** generated files contain no `{{cs.*}}` tokens, **When** output is validated, **Then** no error is raised and Docker Compose `${VAR}` expressions are preserved unmodified.
|
|
211
|
+
4. **Given** a user runs `init` interactively with the postgres overlay, **When** the questionnaire reaches parameters, **Then** the user is prompted for each declared parameter with the default pre-filled.
|
|
212
|
+
|
|
213
|
+
### User Story 2 — Sensitive parameter (P2)
|
|
214
|
+
|
|
215
|
+
A user provides a database password via parameter. The password must not appear in plan output in cleartext.
|
|
216
|
+
|
|
217
|
+
**Acceptance scenarios**:
|
|
218
|
+
|
|
219
|
+
1. **Given** a parameter has `sensitive: true`, **When** the plan command shows parameter values, **Then** the value is displayed as `***`.
|
|
220
|
+
2. **Given** a parameter has `sensitive: true`, **When** the interactive questionnaire prompts for it, **Then** the input is masked.
|
|
221
|
+
|
|
222
|
+
### User Story 3 — Unknown parameter warning (P3)
|
|
223
|
+
|
|
224
|
+
A user adds a parameter in `superposition.yml` that is not declared by any selected overlay.
|
|
225
|
+
|
|
226
|
+
**Acceptance scenarios**:
|
|
227
|
+
|
|
228
|
+
1. **Given** `parameters: { UNKNOWN_PARAM: foo }` in `superposition.yml`, **When** generation runs, **Then** a warning is printed but generation succeeds.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Feature Specification: Split Ollama Service and CLI Overlays
|
|
2
|
+
|
|
3
|
+
**Spec ID**: `012-ollama-cli-overlay`
|
|
4
|
+
**Created**: 2026-04-16
|
|
5
|
+
**Status**: Final
|
|
6
|
+
**Input**: Requirement — split current `ollama` overlay into separate service and CLI overlays, with implicit dependency from `ollama` to `ollama-cli`
|
|
7
|
+
|
|
8
|
+
## Summary
|
|
9
|
+
|
|
10
|
+
Separate Ollama support into two overlays:
|
|
11
|
+
|
|
12
|
+
1. `ollama` — compose-only Ollama server sidecar
|
|
13
|
+
2. `ollama-cli` — CLI-only installation that works in plain and compose stacks
|
|
14
|
+
|
|
15
|
+
Selecting `ollama` must automatically include `ollama-cli` via `requires` so existing behavior is preserved.
|
|
16
|
+
|
|
17
|
+
## Design
|
|
18
|
+
|
|
19
|
+
### Overlay split
|
|
20
|
+
|
|
21
|
+
- `ollama` remains compose-only and owns service wiring (`docker-compose.yml`, API port, sidecar host env)
|
|
22
|
+
- `ollama-cli` owns CLI installation and CLI verification
|
|
23
|
+
- `ollama` declares `requires: [ollama-cli]`
|
|
24
|
+
|
|
25
|
+
### User intent supported
|
|
26
|
+
|
|
27
|
+
- Users can choose only `ollama-cli` in plain stacks when Ollama runs elsewhere (for example on host)
|
|
28
|
+
- Users can still choose `ollama` and get server + CLI automatically
|
|
29
|
+
|
|
30
|
+
## Implementation Scope
|
|
31
|
+
|
|
32
|
+
- Add `overlays/ollama-cli/` with `overlay.yml`, `devcontainer.patch.json`, `setup.sh`, `verify.sh`, `README.md`
|
|
33
|
+
- Update `overlays/ollama/overlay.yml` to require `ollama-cli`
|
|
34
|
+
- Remove CLI installation from `overlays/ollama` and keep service responsibilities there
|
|
35
|
+
- Update tests and changelog entries
|
|
36
|
+
|
|
37
|
+
## User Scenarios & Testing
|
|
38
|
+
|
|
39
|
+
### User Story 1 — Plain stack with remote Ollama
|
|
40
|
+
|
|
41
|
+
1. **Given** a plain stack with `ollama-cli`, **When** generation runs, **Then** the devcontainer contains the `ollama` CLI without requiring a local compose service.
|
|
42
|
+
2. **Given** `OLLAMA_HOST` is configured to a remote endpoint, **When** users run `ollama list`, **Then** requests target that remote server.
|
|
43
|
+
|
|
44
|
+
### User Story 2 — Compose stack with local sidecar
|
|
45
|
+
|
|
46
|
+
1. **Given** a compose stack with `ollama`, **When** generation runs, **Then** `ollama-cli` is auto-added and CLI commands are available in the devcontainer.
|
|
47
|
+
2. **Given** the compose sidecar is running, **When** verification runs, **Then** the service endpoint is reachable via `http://ollama:11434`.
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# Feature Specification: Doctor Overlay Dependency Resolution Check
|
|
2
|
+
|
|
3
|
+
**Spec ID**: `013-doctor-dependency-check`
|
|
4
|
+
**Taxonomy**: `CLI-UX`
|
|
5
|
+
**Created**: 2026-04-24
|
|
6
|
+
**Author**: PM Agent
|
|
7
|
+
**Status**: Approved
|
|
8
|
+
**Input**: Feature assessment — `cs doctor` does not validate that selected overlays satisfy their own dependency requirements; missing `requires:` entries are only caught at regen time.
|
|
9
|
+
|
|
10
|
+
## Problem Statement
|
|
11
|
+
|
|
12
|
+
`cs doctor` checks many things about an existing `.devcontainer/` setup but never validates that
|
|
13
|
+
the overlay set declared in the project file is self-consistent. If a project file includes
|
|
14
|
+
`grafana` but omits the required `prometheus`, the error only surfaces when `cs regen` runs or
|
|
15
|
+
when the user opens the devcontainer. Doctor should catch these problems immediately, with a
|
|
16
|
+
clear message and — where safe — fix them automatically.
|
|
17
|
+
|
|
18
|
+
The same gap applies to `suggests:` (advisory recommendations never surfaced) and to overlays
|
|
19
|
+
listed in the project file that no longer exist in the registry (typos, removed overlays).
|
|
20
|
+
|
|
21
|
+
## Goals
|
|
22
|
+
|
|
23
|
+
- Detect missing `requires:` overlays between the project file's overlay set and the overlay
|
|
24
|
+
registry before regen or container startup.
|
|
25
|
+
- Detect overlay IDs in the project file that are not present in the overlay registry.
|
|
26
|
+
- Surface `suggests:` recommendations as informational notices (not failures).
|
|
27
|
+
- Allow `doctor --fix` to add missing required overlays to the project file and re-run
|
|
28
|
+
generation.
|
|
29
|
+
|
|
30
|
+
## Non-Goals
|
|
31
|
+
|
|
32
|
+
- Validating `conflicts:` — conflict detection already happens during composition.
|
|
33
|
+
- Changing the dependency resolution logic in `composer.ts`.
|
|
34
|
+
- Checking transitive suggestions (only direct `suggests:` from selected overlays).
|
|
35
|
+
|
|
36
|
+
## Design
|
|
37
|
+
|
|
38
|
+
### Dependency resolution check
|
|
39
|
+
|
|
40
|
+
`checkDependencies(overlaysConfig, workingDir)` loads the project file via `loadProjectConfig()`
|
|
41
|
+
and returns early (empty result) if none exists.
|
|
42
|
+
|
|
43
|
+
For each overlay ID in `selection.overlays`:
|
|
44
|
+
|
|
45
|
+
1. **Unknown overlay**: overlay ID not in `overlaysConfig.overlays` → `fail` ("Overlay `<id>`
|
|
46
|
+
not found in registry — it may have been removed or misspelled").
|
|
47
|
+
2. **Missing required overlay**: for each ID in `overlay.requires`, check if the full resolved
|
|
48
|
+
set (project overlays + auto-resolved via `resolveImplicitDependencies`) covers it. If not →
|
|
49
|
+
`fail` ("Overlay `<id>` requires `<dep>` which is not in your project file").
|
|
50
|
+
3. **Missing suggested overlay**: for each ID in `overlay.suggests`, check if it is present in
|
|
51
|
+
the resolved set. If not → `warn` ("Overlay `<id>` suggests `<dep>` — consider adding it for
|
|
52
|
+
better observability / functionality").
|
|
53
|
+
|
|
54
|
+
The check uses the same resolution helpers used by `composer.ts` so the rules are identical.
|
|
55
|
+
|
|
56
|
+
Pass check message: "`N` overlay(s) selected; all dependencies satisfied."
|
|
57
|
+
|
|
58
|
+
### Fix action: `dependency-fix`
|
|
59
|
+
|
|
60
|
+
Registered in `REMEDIATION_REGISTRY`:
|
|
61
|
+
|
|
62
|
+
- **Safety class**: `safe-unattended`
|
|
63
|
+
- **Execution kind**: `regeneration`
|
|
64
|
+
- **Planned changes**:
|
|
65
|
+
- "Add missing required overlay(s) to project file"
|
|
66
|
+
- "Regenerate devcontainer configuration from updated project file"
|
|
67
|
+
|
|
68
|
+
`executeDependencyFix(outputPath, overlaysConfig, overlaysDir, workingDir, silent)`:
|
|
69
|
+
|
|
70
|
+
1. Load project config.
|
|
71
|
+
2. Identify missing required overlays (same logic as the check).
|
|
72
|
+
3. Add them to `selection.overlays`.
|
|
73
|
+
4. Write updated project file with `writeProjectConfig()`.
|
|
74
|
+
5. Rebuild answers from updated config and call `composeDevContainer()`.
|
|
75
|
+
6. Re-check: verify no dependency failures remain.
|
|
76
|
+
|
|
77
|
+
Unknown overlay IDs (not in registry) are **not** auto-fixable — marked `manual-only`.
|
|
78
|
+
Suggested overlays are never auto-added — always `not-applicable`.
|
|
79
|
+
|
|
80
|
+
### DoctorReport changes
|
|
81
|
+
|
|
82
|
+
`DoctorReport` gains a `dependencies: CheckResult[]` field.
|
|
83
|
+
`generateReport()` gains a `dependenciesChecks` parameter.
|
|
84
|
+
`formatAsText()` gains a "Dependencies" section that shows failures and warnings;
|
|
85
|
+
suppresses the section entirely if all pass.
|
|
86
|
+
`reportToFindings()` includes `checksToFindings(report.dependencies, 'manifest', 'full')`.
|
|
87
|
+
`executeFixRun()` calls `checkDependencies()` in the re-check pass.
|
|
88
|
+
|
|
89
|
+
### Affected files
|
|
90
|
+
|
|
91
|
+
| File | Change |
|
|
92
|
+
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
93
|
+
| `tool/commands/doctor.ts` | Add `checkDependencies()`, `executeDependencyFix()`, wire into report infrastructure, `REMEDIATION_REGISTRY`, `PRIORITY` map |
|
|
94
|
+
| `tool/__tests__/commands.test.ts` | Tests for unknown overlay, missing required, suggestion warn, fix action |
|
|
95
|
+
| `CHANGELOG.md` | Entry under `### Added` |
|
|
96
|
+
|
|
97
|
+
### User-visible behaviour
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
Dependencies:
|
|
101
|
+
✗ Overlay grafana requires prometheus which is not in your project file
|
|
102
|
+
→ Add prometheus to the overlays: list in .superposition.yml
|
|
103
|
+
→ Fixable with --fix flag
|
|
104
|
+
⚠ Overlay postgres suggests grafana — consider adding it for observability
|
|
105
|
+
✓ All other overlay dependencies satisfied
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Backward compatibility
|
|
109
|
+
|
|
110
|
+
No changes to existing generated files or project file format. Purely additive check.
|
|
111
|
+
|
|
112
|
+
## User Scenarios & Testing
|
|
113
|
+
|
|
114
|
+
### User Story 1 — Missing required overlay detected and fixed (P1)
|
|
115
|
+
|
|
116
|
+
A developer has `grafana` in their project file but forgot to add `prometheus` (which grafana
|
|
117
|
+
requires). They run `cs doctor` and immediately see the problem instead of discovering it when
|
|
118
|
+
the devcontainer fails to build.
|
|
119
|
+
|
|
120
|
+
**Why this priority**: Missing required overlays cause silent failures at startup. This is the
|
|
121
|
+
most actionable fix doctor can offer — it unblocks the user immediately.
|
|
122
|
+
|
|
123
|
+
**Independent Test**: Write a `.superposition.yml` selecting `grafana` without `prometheus`.
|
|
124
|
+
Run `doctorCommand`. Assert output contains dependency failure mentioning `prometheus`.
|
|
125
|
+
|
|
126
|
+
**Acceptance Scenarios**:
|
|
127
|
+
|
|
128
|
+
1. **Given** a project file with `overlays: [grafana]`, **When** `cs doctor` runs, **Then** a
|
|
129
|
+
`fail` finding reports "`grafana` requires `prometheus` which is not in your project file".
|
|
130
|
+
2. **Given** the same setup with `--fix`, **When** doctor runs, **Then** `prometheus` is added
|
|
131
|
+
to the project file and `cs regen` is run automatically; the final check passes.
|
|
132
|
+
3. **Given** a project file with `overlays: [grafana, prometheus]`, **When** `cs doctor` runs,
|
|
133
|
+
**Then** the dependencies section shows a pass with no failures.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
### User Story 2 — Unknown overlay ID caught (P2)
|
|
138
|
+
|
|
139
|
+
A developer misspells an overlay ID (`nodjs` instead of `nodejs`) in their project file. Doctor
|
|
140
|
+
catches it immediately rather than letting it silently be ignored during generation.
|
|
141
|
+
|
|
142
|
+
**Why this priority**: Typos in the project file produce no error today — the overlay is simply
|
|
143
|
+
not applied. Doctor should surface this.
|
|
144
|
+
|
|
145
|
+
**Independent Test**: Write a `.superposition.yml` with `overlays: [nodjs]`. Run
|
|
146
|
+
`doctorCommand`. Assert a `fail` finding mentioning `nodjs` not found in registry.
|
|
147
|
+
|
|
148
|
+
**Acceptance Scenarios**:
|
|
149
|
+
|
|
150
|
+
1. **Given** `overlays: [nodjs]` in project file, **When** `cs doctor` runs, **Then** a `fail`
|
|
151
|
+
finding reports "`nodjs` not found in overlay registry — check for typos".
|
|
152
|
+
2. **Given** `overlays: [nodejs]`, **When** `cs doctor` runs, **Then** no unknown-overlay
|
|
153
|
+
failure appears.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
### User Story 3 — Suggestions surfaced as informational (P3)
|
|
158
|
+
|
|
159
|
+
A user has `postgres` selected. The postgres overlay suggests `prometheus` and `grafana` for
|
|
160
|
+
observability. Doctor shows these as soft recommendations, not failures.
|
|
161
|
+
|
|
162
|
+
**Why this priority**: Suggestions are optional by definition; showing them as warnings without
|
|
163
|
+
blocking is a quality-of-life improvement.
|
|
164
|
+
|
|
165
|
+
**Independent Test**: Write a `.superposition.yml` with `overlays: [postgres]` (postgres
|
|
166
|
+
suggests `prometheus`, `grafana`). Run `doctorCommand`. Assert warn-level findings for each
|
|
167
|
+
suggestion, no failures.
|
|
168
|
+
|
|
169
|
+
**Acceptance Scenarios**:
|
|
170
|
+
|
|
171
|
+
1. **Given** `overlays: [postgres]` (postgres suggests prometheus, grafana), **When** `cs doctor`
|
|
172
|
+
runs, **Then** two `warn` findings appear suggesting prometheus and grafana; no failure.
|
|
173
|
+
2. **Given** `overlays: [postgres, prometheus, grafana]`, **When** `cs doctor` runs, **Then** no
|
|
174
|
+
suggestion warnings appear for postgres.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
### Edge Cases
|
|
179
|
+
|
|
180
|
+
- Project file with no overlays: return a single pass ("no overlays selected").
|
|
181
|
+
- Overlay that requires itself: guard against infinite recursion (not expected but safe to handle).
|
|
182
|
+
- `requires:` chain (A requires B which requires C, project has A and C but not B): each missing
|
|
183
|
+
level reported individually.
|
|
184
|
+
- Auto-resolved dependencies already in the manifest but not in the project file: not flagged
|
|
185
|
+
(the resolver adds them automatically; this mirrors drift-check behaviour).
|
|
186
|
+
|
|
187
|
+
## Requirements
|
|
188
|
+
|
|
189
|
+
### Functional Requirements
|
|
190
|
+
|
|
191
|
+
- **FR-001**: `checkDependencies()` MUST return `fail` for each overlay in the project file that
|
|
192
|
+
references a non-existent registry ID.
|
|
193
|
+
- **FR-002**: `checkDependencies()` MUST return `fail` for each `requires:` entry of a selected
|
|
194
|
+
overlay that is absent from the resolved overlay set.
|
|
195
|
+
- **FR-003**: `checkDependencies()` MUST return `warn` for each `suggests:` entry of a selected
|
|
196
|
+
overlay that is absent from the resolved overlay set.
|
|
197
|
+
- **FR-004**: `executeDependencyFix()` MUST add missing required overlays to the project file
|
|
198
|
+
and regenerate; it MUST NOT add suggested overlays.
|
|
199
|
+
- **FR-005**: Unknown overlay IDs MUST be marked `manual-only` (no auto-fix).
|
|
200
|
+
- **FR-006**: The check MUST use the same dependency resolution logic as `composer.ts` (no
|
|
201
|
+
duplication; shared helpers).
|
|
202
|
+
- **FR-007**: When no project file is present, the check MUST return an empty result (no noise).
|
|
203
|
+
|
|
204
|
+
### Key Entities
|
|
205
|
+
|
|
206
|
+
- **ResolvedOverlaySet**: the set of overlay IDs after implicit dependency resolution — used as
|
|
207
|
+
the reference for missing-dep detection.
|
|
208
|
+
- **DependencyFinding**: a `CheckResult` enriched with `sourceOverlay` and `missingOverlay` for
|
|
209
|
+
accurate error messages.
|
|
210
|
+
|
|
211
|
+
## Dependencies & Impact
|
|
212
|
+
|
|
213
|
+
- **Affected Areas**: `tool/commands/doctor.ts`, `tool/__tests__/commands.test.ts`, `CHANGELOG.md`
|
|
214
|
+
- **Compatibility Impact**: None — purely additive new check category.
|
|
215
|
+
- **Required Documentation Updates**: `CHANGELOG.md`
|
|
216
|
+
- **Verification Plan**: Unit tests in `commands.test.ts`; manual test with a project file that
|
|
217
|
+
has a real missing dependency.
|
|
218
|
+
|
|
219
|
+
## Success Criteria
|
|
220
|
+
|
|
221
|
+
### Measurable Outcomes
|
|
222
|
+
|
|
223
|
+
- **SC-001**: `cs doctor` on a project file missing a `requires:` dependency reports a `fail`
|
|
224
|
+
within the Dependencies section within the existing doctor runtime (no perceptible extra
|
|
225
|
+
latency).
|
|
226
|
+
- **SC-002**: `cs doctor --fix` on the same setup produces a project file with the missing overlay
|
|
227
|
+
added and a passing re-check.
|
|
228
|
+
- **SC-003**: `npm test` passes with at least 3 new test cases covering: unknown ID, missing
|
|
229
|
+
required, suggestion warn.
|
|
230
|
+
- **SC-004**: No existing doctor tests regress.
|
|
231
|
+
|
|
232
|
+
## Open Questions
|
|
233
|
+
|
|
234
|
+
| # | Question | Owner | Resolution |
|
|
235
|
+
| --- | ------------------------------------------------------------------------------- | ----- | ------------------------------------------------ |
|
|
236
|
+
| 1 | Should transitive `suggests` (suggests of suggests) be surfaced or only direct? | PM | Pending — lean toward direct only to avoid noise |
|
|
237
|
+
| 2 | Should `dependency-fix` add suggested overlays when user passes `--suggest`? | PM | Pending |
|
|
238
|
+
|
|
239
|
+
## Out of Scope
|
|
240
|
+
|
|
241
|
+
- Changing the dependency resolver in `composer.ts`.
|
|
242
|
+
- Validating that `conflicts:` declarations are bidirectional (already covered by `overlay-consistency` agent).
|
|
243
|
+
- Surfacing overlay version constraints (overlays don't have versions today).
|
|
244
|
+
|
|
245
|
+
## Implementation Notes
|
|
246
|
+
|
|
247
|
+
- `checkDependencies` reads raw YAML as a fallback when `loadProjectConfig` throws for unknown overlay IDs, allowing the check to detect the unknown ID itself.
|
|
248
|
+
- Comparison is against `projectFileSet` (the overlay IDs explicitly listed in the project file), not the resolved set — otherwise transitive auto-resolved dependencies would always appear satisfied.
|
|
249
|
+
- `suggests` mismatches are surfaced as `warn`; `requires` mismatches as `fail` with `fixable: true` and remediation key `dependency-fix`.
|
|
250
|
+
- The Dependencies section in `formatAsText` shows the pass summary alongside any suggestion warnings (i.e., the pass line is shown when there are no `fail` results, even if `warn` results exist).
|