container-superposition 0.1.3 → 0.1.5
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 +72 -1014
- package/dist/scripts/init.js +512 -238
- package/dist/scripts/init.js.map +1 -1
- package/dist/tool/commands/adopt.d.ts +62 -0
- package/dist/tool/commands/adopt.d.ts.map +1 -0
- package/dist/tool/commands/adopt.js +767 -0
- package/dist/tool/commands/adopt.js.map +1 -0
- package/dist/tool/commands/doctor.js +2 -2
- package/dist/tool/commands/explain.d.ts.map +1 -1
- package/dist/tool/commands/explain.js +88 -0
- package/dist/tool/commands/explain.js.map +1 -1
- package/dist/tool/commands/hash.d.ts +36 -0
- package/dist/tool/commands/hash.d.ts.map +1 -0
- package/dist/tool/commands/hash.js +242 -0
- package/dist/tool/commands/hash.js.map +1 -0
- package/dist/tool/commands/plan.d.ts +53 -0
- package/dist/tool/commands/plan.d.ts.map +1 -1
- package/dist/tool/commands/plan.js +784 -42
- package/dist/tool/commands/plan.js.map +1 -1
- package/dist/tool/questionnaire/composer.d.ts +12 -3
- package/dist/tool/questionnaire/composer.d.ts.map +1 -1
- package/dist/tool/questionnaire/composer.js +133 -20
- package/dist/tool/questionnaire/composer.js.map +1 -1
- package/dist/tool/schema/project-config.d.ts +15 -0
- package/dist/tool/schema/project-config.d.ts.map +1 -0
- package/dist/tool/schema/project-config.js +359 -0
- package/dist/tool/schema/project-config.js.map +1 -0
- package/dist/tool/schema/types.d.ts +57 -1
- package/dist/tool/schema/types.d.ts.map +1 -1
- package/dist/tool/utils/backup.d.ts +23 -0
- package/dist/tool/utils/backup.d.ts.map +1 -0
- package/dist/tool/utils/backup.js +123 -0
- package/dist/tool/utils/backup.js.map +1 -0
- package/dist/tool/utils/gitignore.d.ts +15 -0
- package/dist/tool/utils/gitignore.d.ts.map +1 -0
- package/dist/tool/utils/gitignore.js +41 -0
- package/dist/tool/utils/gitignore.js.map +1 -0
- package/dist/tool/utils/services-export.d.ts +14 -0
- package/dist/tool/utils/services-export.d.ts.map +1 -0
- package/dist/tool/utils/services-export.js +478 -0
- package/dist/tool/utils/services-export.js.map +1 -0
- package/dist/tool/utils/summary.d.ts +69 -0
- package/dist/tool/utils/summary.d.ts.map +1 -0
- package/dist/tool/utils/summary.js +260 -0
- package/dist/tool/utils/summary.js.map +1 -0
- package/docs/README.md +12 -2
- package/docs/adopt.md +196 -0
- package/docs/custom-patches.md +1 -1
- package/docs/discovery-commands.md +55 -3
- package/docs/examples.md +40 -6
- package/docs/filesystem-contract.md +58 -0
- package/docs/hash.md +183 -0
- package/docs/minimal-and-editor.md +1 -1
- package/docs/overlays.md +108 -5
- package/docs/presets-architecture.md +1 -1
- package/docs/presets.md +1 -1
- package/docs/publishing.md +36 -23
- package/docs/security.md +43 -0
- package/docs/specs/001-verbose-plan-graph/checklists/requirements.md +36 -0
- package/docs/specs/001-verbose-plan-graph/contracts/plan-verbose-output.md +96 -0
- package/docs/specs/001-verbose-plan-graph/data-model.md +111 -0
- package/docs/specs/001-verbose-plan-graph/plan.md +127 -0
- package/docs/specs/001-verbose-plan-graph/quickstart.md +106 -0
- package/docs/specs/001-verbose-plan-graph/research.md +100 -0
- package/docs/specs/001-verbose-plan-graph/spec.md +128 -0
- package/docs/specs/001-verbose-plan-graph/tasks.md +223 -0
- package/docs/specs/002-superposition-config-file/checklists/requirements.md +36 -0
- package/docs/specs/002-superposition-config-file/contracts/init-project-config.md +98 -0
- package/docs/specs/002-superposition-config-file/data-model.md +126 -0
- package/docs/specs/002-superposition-config-file/plan.md +208 -0
- package/docs/specs/002-superposition-config-file/quickstart.md +140 -0
- package/docs/specs/002-superposition-config-file/research.md +144 -0
- package/docs/specs/002-superposition-config-file/spec.md +130 -0
- package/docs/specs/002-superposition-config-file/tasks.md +213 -0
- package/docs/team-workflow.md +27 -1
- package/docs/workflows.md +136 -0
- package/overlays/.presets/microservice.yml +32 -6
- package/overlays/.presets/sdd.yml +84 -0
- package/overlays/.presets/web-api.yml +76 -56
- package/overlays/README.md +7 -1
- package/overlays/amp/README.md +70 -0
- package/overlays/amp/devcontainer.patch.json +3 -0
- package/overlays/amp/overlay.yml +15 -0
- package/overlays/amp/setup.sh +21 -0
- package/overlays/amp/verify.sh +21 -0
- package/overlays/claude-code/README.md +83 -0
- package/overlays/claude-code/devcontainer.patch.json +3 -0
- package/overlays/claude-code/overlay.yml +15 -0
- package/overlays/claude-code/setup.sh +21 -0
- package/overlays/claude-code/verify.sh +21 -0
- package/overlays/cloudflared/README.md +190 -0
- package/overlays/cloudflared/devcontainer.patch.json +3 -0
- package/overlays/cloudflared/overlay.yml +15 -0
- package/overlays/cloudflared/setup.sh +49 -0
- package/overlays/cloudflared/verify.sh +21 -0
- package/overlays/direnv/README.md +6 -4
- package/overlays/direnv/setup.sh +0 -12
- package/overlays/gemini-cli/README.md +77 -0
- package/overlays/gemini-cli/devcontainer.patch.json +3 -0
- package/overlays/gemini-cli/overlay.yml +15 -0
- package/overlays/gemini-cli/setup.sh +21 -0
- package/overlays/gemini-cli/verify.sh +21 -0
- package/overlays/grpc-tools/README.md +242 -0
- package/overlays/grpc-tools/devcontainer.patch.json +14 -0
- package/overlays/grpc-tools/overlay.yml +14 -0
- package/overlays/grpc-tools/setup.sh +57 -0
- package/overlays/grpc-tools/verify.sh +47 -0
- package/overlays/keycloak/.env.example +5 -0
- package/overlays/keycloak/README.md +238 -0
- package/overlays/keycloak/devcontainer.patch.json +17 -0
- package/overlays/keycloak/docker-compose.yml +32 -0
- package/overlays/keycloak/overlay.yml +23 -0
- package/overlays/keycloak/verify.sh +54 -0
- package/overlays/mailpit/.env.example +4 -0
- package/overlays/mailpit/README.md +191 -0
- package/overlays/mailpit/devcontainer.patch.json +20 -0
- package/overlays/mailpit/docker-compose.yml +17 -0
- package/overlays/mailpit/overlay.yml +26 -0
- package/overlays/mailpit/verify.sh +52 -0
- package/overlays/ngrok/overlay.yml +2 -1
- package/overlays/opencode/README.md +76 -0
- package/overlays/opencode/devcontainer.patch.json +3 -0
- package/overlays/opencode/overlay.yml +14 -0
- package/overlays/opencode/setup.sh +21 -0
- package/overlays/opencode/verify.sh +21 -0
- package/overlays/python/README.md +51 -35
- package/overlays/python/devcontainer.patch.json +7 -4
- package/overlays/python/setup.sh +50 -23
- package/overlays/python/verify.sh +29 -1
- package/overlays/spec-kit/README.md +181 -0
- package/overlays/spec-kit/devcontainer.patch.json +6 -0
- package/overlays/spec-kit/overlay.yml +19 -0
- package/overlays/spec-kit/setup.sh +45 -0
- package/overlays/spec-kit/verify.sh +33 -0
- package/overlays/windsurf-cli/README.md +69 -0
- package/overlays/windsurf-cli/devcontainer.patch.json +3 -0
- package/overlays/windsurf-cli/overlay.yml +15 -0
- package/overlays/windsurf-cli/setup.sh +21 -0
- package/overlays/windsurf-cli/verify.sh +21 -0
- package/package.json +1 -1
- package/tool/schema/config.schema.json +138 -9
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Summary utilities for post-generation output
|
|
3
|
+
*/
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import boxen from 'boxen';
|
|
6
|
+
import { generateUrl } from './port-utils.js';
|
|
7
|
+
/**
|
|
8
|
+
* Detect warnings based on selected overlays and configuration
|
|
9
|
+
*/
|
|
10
|
+
export function detectWarnings(overlays, answers) {
|
|
11
|
+
const warnings = [];
|
|
12
|
+
// Check for docker-sock security warning
|
|
13
|
+
const hasDockerSock = overlays.some((o) => o.id === 'docker-sock');
|
|
14
|
+
if (hasDockerSock) {
|
|
15
|
+
warnings.push('docker-sock overlay provides root access to host Docker daemon\n Use only for trusted code. Consider docker-in-docker for isolation.');
|
|
16
|
+
}
|
|
17
|
+
// Check for target mismatch
|
|
18
|
+
const target = answers.target || 'local';
|
|
19
|
+
if (hasDockerSock && target === 'codespaces') {
|
|
20
|
+
warnings.push('docker-sock may not work in GitHub Codespaces\n Consider using docker-in-docker instead.');
|
|
21
|
+
}
|
|
22
|
+
// Check for high port count
|
|
23
|
+
const portCount = overlays.reduce((count, o) => count + (o.ports?.length || 0), 0);
|
|
24
|
+
const hasHighPortCountWarning = portCount > 10;
|
|
25
|
+
if (hasHighPortCountWarning) {
|
|
26
|
+
warnings.push(`High port count (${portCount} ports) may cause conflicts\n Consider using --port-offset to avoid conflicts with other projects.`);
|
|
27
|
+
}
|
|
28
|
+
// Check for no port offset with multiple services
|
|
29
|
+
const hasServices = overlays.some((o) => o.category === 'database' || o.category === 'observability');
|
|
30
|
+
if (!hasHighPortCountWarning &&
|
|
31
|
+
hasServices &&
|
|
32
|
+
(!answers.portOffset || answers.portOffset === 0)) {
|
|
33
|
+
warnings.push('Running multiple devcontainers simultaneously may cause port conflicts\n Use --port-offset 100 (or higher) to avoid conflicts.');
|
|
34
|
+
}
|
|
35
|
+
return warnings;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Generate helpful tips based on configuration
|
|
39
|
+
*/
|
|
40
|
+
export function generateTips(overlays, answers) {
|
|
41
|
+
const tips = [];
|
|
42
|
+
// Suggest committing manifest
|
|
43
|
+
if (!answers.preset) {
|
|
44
|
+
tips.push('Commit superposition.json to enable team regeneration');
|
|
45
|
+
}
|
|
46
|
+
// Suggest customization directory
|
|
47
|
+
const hasCustomDir = overlays.length > 3;
|
|
48
|
+
if (hasCustomDir) {
|
|
49
|
+
tips.push('Preserve customizations in .devcontainer/custom/');
|
|
50
|
+
}
|
|
51
|
+
// Suggest regen command
|
|
52
|
+
tips.push('Regenerate anytime: npx container-superposition regen');
|
|
53
|
+
return tips;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Generate next steps based on mode
|
|
57
|
+
*/
|
|
58
|
+
export function generateNextSteps(isManifestOnly, isRegen) {
|
|
59
|
+
if (isManifestOnly) {
|
|
60
|
+
return [
|
|
61
|
+
'Review the generated superposition.json file',
|
|
62
|
+
'Commit it to your repository',
|
|
63
|
+
'Team members can run "npx container-superposition regen"',
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
if (isRegen) {
|
|
67
|
+
return [
|
|
68
|
+
'Rebuild container:\n Open Command Palette (Ctrl+Shift+P / Cmd+Shift+P) → "Dev Containers: Rebuild Container"',
|
|
69
|
+
'Test changes manually',
|
|
70
|
+
'Review any customizations in .devcontainer/custom/',
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
return [
|
|
74
|
+
'Customize environment:\n cp .devcontainer/.env.example .devcontainer/.env',
|
|
75
|
+
'Open in VS Code:\n code .',
|
|
76
|
+
'Reopen in Container:\n Open Command Palette (Ctrl+Shift+P / Cmd+Shift+P) → "Dev Containers: Reopen in Container"',
|
|
77
|
+
'Verify setup:\n npx container-superposition doctor',
|
|
78
|
+
];
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Convert overlay metadata to service info
|
|
82
|
+
*/
|
|
83
|
+
export function overlaysToServices(overlays) {
|
|
84
|
+
return overlays.map((overlay) => {
|
|
85
|
+
// Extract version from name if present (e.g., "PostgreSQL 16" -> version: "16")
|
|
86
|
+
const versionMatch = overlay.name.match(/\d+(?:\.\d+)?/);
|
|
87
|
+
const version = versionMatch ? versionMatch[0] : undefined;
|
|
88
|
+
return {
|
|
89
|
+
name: overlay.name,
|
|
90
|
+
category: overlay.category,
|
|
91
|
+
version,
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Convert normalized ports to port info with URLs
|
|
97
|
+
*/
|
|
98
|
+
export function portsToPortInfo(ports, connectionStrings) {
|
|
99
|
+
return ports.map((port) => {
|
|
100
|
+
const service = port.service || 'unknown';
|
|
101
|
+
const url = generateUrl(port);
|
|
102
|
+
// Try to find connection string for this service
|
|
103
|
+
let connectionString;
|
|
104
|
+
if (connectionStrings[service]) {
|
|
105
|
+
connectionString = connectionStrings[service];
|
|
106
|
+
}
|
|
107
|
+
else if (connectionStrings[`${service}-url`]) {
|
|
108
|
+
connectionString = connectionStrings[`${service}-url`];
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
service,
|
|
112
|
+
port: port.port,
|
|
113
|
+
actualPort: port.actualPort,
|
|
114
|
+
url,
|
|
115
|
+
connectionString,
|
|
116
|
+
};
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Format and print generation summary.
|
|
121
|
+
*
|
|
122
|
+
* @param summary The generation summary to render.
|
|
123
|
+
* @param quiet When true, suppresses all console output. This parameter is
|
|
124
|
+
* reserved for callers (for example, CLI commands or tests)
|
|
125
|
+
* that need to generate a summary object but handle user
|
|
126
|
+
* messaging themselves.
|
|
127
|
+
*/
|
|
128
|
+
export function printSummary(summary, quiet = false) {
|
|
129
|
+
// If quiet mode is enabled, skip printing while still allowing callers
|
|
130
|
+
// to invoke this function consistently. See the JSDoc for intended usage.
|
|
131
|
+
if (quiet) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const lines = [];
|
|
135
|
+
// Header
|
|
136
|
+
const title = summary.isManifestOnly
|
|
137
|
+
? '📋 Manifest Generated'
|
|
138
|
+
: summary.backupPath
|
|
139
|
+
? '🔄 DevContainer Regenerated'
|
|
140
|
+
: '✨ DevContainer Generated';
|
|
141
|
+
lines.push(chalk.bold.green(title));
|
|
142
|
+
lines.push('');
|
|
143
|
+
// Backup notification (for regen)
|
|
144
|
+
if (summary.backupPath) {
|
|
145
|
+
lines.push(chalk.yellow(`Backup created: ${summary.backupPath}`));
|
|
146
|
+
lines.push('');
|
|
147
|
+
}
|
|
148
|
+
// Files created (manifest-only shows just manifest)
|
|
149
|
+
if (summary.isManifestOnly) {
|
|
150
|
+
lines.push(chalk.white('Manifest:'));
|
|
151
|
+
lines.push(chalk.gray(` ${summary.manifestPath || 'superposition.json'}`));
|
|
152
|
+
lines.push('');
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
lines.push(chalk.white('Files created:'));
|
|
156
|
+
for (const file of summary.files.slice(0, 8)) {
|
|
157
|
+
lines.push(chalk.gray(` ${file}`));
|
|
158
|
+
}
|
|
159
|
+
if (summary.files.length > 8) {
|
|
160
|
+
lines.push(chalk.gray(` ... and ${summary.files.length - 8} more`));
|
|
161
|
+
}
|
|
162
|
+
lines.push('');
|
|
163
|
+
}
|
|
164
|
+
// Services included
|
|
165
|
+
if (summary.services.length > 0) {
|
|
166
|
+
lines.push(chalk.white('Services included:'));
|
|
167
|
+
const displayServices = summary.services.slice(0, 10);
|
|
168
|
+
for (const service of displayServices) {
|
|
169
|
+
const versionStr = service.version ? ` ${service.version}` : '';
|
|
170
|
+
const categoryStr = chalk.dim(` (${service.category})`);
|
|
171
|
+
lines.push(chalk.green(` ✓ ${service.name}${versionStr}`) + categoryStr);
|
|
172
|
+
}
|
|
173
|
+
if (summary.services.length > 10) {
|
|
174
|
+
lines.push(chalk.gray(` ... and ${summary.services.length - 10} more`));
|
|
175
|
+
}
|
|
176
|
+
lines.push('');
|
|
177
|
+
}
|
|
178
|
+
// Port mappings and service URLs
|
|
179
|
+
if (summary.ports.length > 0) {
|
|
180
|
+
lines.push(chalk.white('🌐 Service Access'));
|
|
181
|
+
lines.push('');
|
|
182
|
+
// Group by HTTP services and database services
|
|
183
|
+
const httpPorts = summary.ports.filter((p) => p.url);
|
|
184
|
+
const dbPorts = summary.ports.filter((p) => p.connectionString && !p.url);
|
|
185
|
+
// Show application/HTTP services first
|
|
186
|
+
if (httpPorts.length > 0) {
|
|
187
|
+
for (const port of httpPorts) {
|
|
188
|
+
const label = port.service.charAt(0).toUpperCase() + port.service.slice(1);
|
|
189
|
+
lines.push(chalk.cyan(` ${label}:`));
|
|
190
|
+
lines.push(chalk.gray(` ${port.url}`));
|
|
191
|
+
}
|
|
192
|
+
lines.push('');
|
|
193
|
+
}
|
|
194
|
+
// Show database/infrastructure services
|
|
195
|
+
if (dbPorts.length > 0) {
|
|
196
|
+
lines.push(chalk.white(' Infrastructure:'));
|
|
197
|
+
for (const port of dbPorts) {
|
|
198
|
+
const label = port.service.charAt(0).toUpperCase() + port.service.slice(1);
|
|
199
|
+
lines.push(chalk.cyan(` ${label}:`));
|
|
200
|
+
lines.push(chalk.gray(` ${port.connectionString}`));
|
|
201
|
+
}
|
|
202
|
+
lines.push('');
|
|
203
|
+
}
|
|
204
|
+
// Port offset info
|
|
205
|
+
if (summary.portOffset > 0) {
|
|
206
|
+
lines.push(chalk.dim(` Port offset: ${summary.portOffset}`));
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
lines.push(chalk.dim(' Port offset: 0 (use --port-offset to avoid conflicts)'));
|
|
210
|
+
}
|
|
211
|
+
lines.push('');
|
|
212
|
+
}
|
|
213
|
+
// Warnings
|
|
214
|
+
if (summary.warnings.length > 0) {
|
|
215
|
+
lines.push(chalk.yellow('⚠️ Warnings'));
|
|
216
|
+
lines.push('');
|
|
217
|
+
for (const warning of summary.warnings) {
|
|
218
|
+
const warningLines = warning.split('\n');
|
|
219
|
+
lines.push(chalk.yellow(` • ${warningLines[0]}`));
|
|
220
|
+
for (let i = 1; i < warningLines.length; i++) {
|
|
221
|
+
lines.push(chalk.dim(` ${warningLines[i]}`));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
lines.push('');
|
|
225
|
+
}
|
|
226
|
+
// Tips
|
|
227
|
+
if (summary.tips.length > 0) {
|
|
228
|
+
lines.push(chalk.cyan('💡 Tips'));
|
|
229
|
+
lines.push('');
|
|
230
|
+
for (const tip of summary.tips) {
|
|
231
|
+
lines.push(chalk.gray(` • ${tip}`));
|
|
232
|
+
}
|
|
233
|
+
lines.push('');
|
|
234
|
+
}
|
|
235
|
+
// Next steps
|
|
236
|
+
lines.push(chalk.white('📝 Next Steps'));
|
|
237
|
+
lines.push('');
|
|
238
|
+
for (let i = 0; i < summary.nextSteps.length; i++) {
|
|
239
|
+
const step = summary.nextSteps[i];
|
|
240
|
+
const stepLines = step.split('\n');
|
|
241
|
+
lines.push(chalk.gray(` ${i + 1}. ${stepLines[0]}`));
|
|
242
|
+
for (let j = 1; j < stepLines.length; j++) {
|
|
243
|
+
lines.push(chalk.dim(` ${stepLines[j]}`));
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
// Footer
|
|
247
|
+
if (!summary.isManifestOnly) {
|
|
248
|
+
lines.push('');
|
|
249
|
+
lines.push(chalk.dim(`Generated in .devcontainer/ • Manifest: ${summary.manifestPath || 'superposition.json'}`));
|
|
250
|
+
}
|
|
251
|
+
// Print with boxen
|
|
252
|
+
console.log('\n' +
|
|
253
|
+
boxen(lines.join('\n'), {
|
|
254
|
+
padding: 1,
|
|
255
|
+
borderColor: 'green',
|
|
256
|
+
borderStyle: 'round',
|
|
257
|
+
margin: 1,
|
|
258
|
+
}));
|
|
259
|
+
}
|
|
260
|
+
//# sourceMappingURL=summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../../../tool/utils/summary.ts"],"names":[],"mappings":"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"}
|
package/docs/README.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Complete documentation for the container-superposition devcontainer scaffolding system.
|
|
4
4
|
|
|
5
|
+
## Spec-First Development
|
|
6
|
+
|
|
7
|
+
Feature work is governed by specs committed under `docs/specs/`. Implementation
|
|
8
|
+
must not begin until the relevant spec is committed and reviewed.
|
|
9
|
+
|
|
5
10
|
## 📚 Documentation Index
|
|
6
11
|
|
|
7
12
|
### Getting Started
|
|
@@ -19,10 +24,15 @@ Complete documentation for the container-superposition devcontainer scaffolding
|
|
|
19
24
|
|
|
20
25
|
### User Guides
|
|
21
26
|
|
|
27
|
+
- **[Adopt Command](adopt.md)** - Migrate an existing `.devcontainer/` to the overlay-based workflow
|
|
28
|
+
- **[Hash Command](hash.md)** - Deterministic environment fingerprint for drift detection and reproducibility
|
|
22
29
|
- **[Presets Guide](presets.md)** - Using stack presets for common development scenarios
|
|
23
30
|
- **[Messaging Comparison](messaging-comparison.md)** - Choosing between RabbitMQ, Redpanda, and NATS
|
|
24
31
|
- **[Messaging Quick Start](messaging-quick-start.md)** - Getting started with messaging overlays
|
|
25
32
|
- **[Observability Workflow](observability-workflow.md)** - Setting up monitoring and tracing
|
|
33
|
+
- **[Workflows and Regeneration](workflows.md)** - Regeneration, backups, and manifest-based workflows
|
|
34
|
+
- **[Filesystem Contract](filesystem-contract.md)** - What the tool writes and what to edit
|
|
35
|
+
- **[Security Considerations](security.md)** - Development-only risks and best practices
|
|
26
36
|
|
|
27
37
|
### Development
|
|
28
38
|
|
|
@@ -209,7 +219,7 @@ When published to npm, includes:
|
|
|
209
219
|
- ✅ Type definitions and schema (`tool/schema/`)
|
|
210
220
|
- ✅ Documentation
|
|
211
221
|
|
|
212
|
-
**Package size**:
|
|
222
|
+
**Package size**: Varies by release (use `npm pack --dry-run`)
|
|
213
223
|
|
|
214
224
|
## 🤝 Contributing
|
|
215
225
|
|
|
@@ -228,7 +238,7 @@ MIT - See [LICENSE](../LICENSE)
|
|
|
228
238
|
|
|
229
239
|
- **Repository**: <https://github.com/veggerby/container-superposition>
|
|
230
240
|
- **Issues**: <https://github.com/veggerby/container-superposition/issues>
|
|
231
|
-
- **npm Package**: <https://www.npmjs.com/package/container-superposition>
|
|
241
|
+
- **npm Package**: <https://www.npmjs.com/package/container-superposition>
|
|
232
242
|
|
|
233
243
|
## 🆘 Support
|
|
234
244
|
|
package/docs/adopt.md
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Adopt Command
|
|
2
|
+
|
|
3
|
+
The `adopt` command helps you **migrate an existing `.devcontainer/` configuration** to Container Superposition's overlay-based workflow.
|
|
4
|
+
|
|
5
|
+
It scans your current `devcontainer.json` and any linked `docker-compose.yml` files, matches their contents against all available overlays, and produces:
|
|
6
|
+
|
|
7
|
+
1. **`superposition.json`** — the manifest written to the **project root** (next to your `src/`, `package.json`, etc.), ready to commit and share with your team
|
|
8
|
+
2. **`.devcontainer/custom/devcontainer.patch.json`** — any config that has no overlay equivalent (custom features, extensions, mounts, remoteEnv, etc.)
|
|
9
|
+
3. **`.devcontainer/custom/docker-compose.patch.yml`** — any compose services that have no overlay equivalent
|
|
10
|
+
|
|
11
|
+
The custom patches in `custom/` are automatically merged on every `regen`, so your project-specific configuration is never lost.
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Analyse your existing .devcontainer/ (prints a report, writes nothing)
|
|
17
|
+
npx container-superposition adopt --dry-run
|
|
18
|
+
|
|
19
|
+
# Run the analysis and write the generated files
|
|
20
|
+
npx container-superposition adopt
|
|
21
|
+
|
|
22
|
+
# Force-overwrite any existing superposition.json / custom/ files
|
|
23
|
+
npx container-superposition adopt --force
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Docker Compose Devcontainers
|
|
27
|
+
|
|
28
|
+
`adopt` fully supports compose-based devcontainers. It reads the
|
|
29
|
+
`dockerComposeFile` field in `devcontainer.json` to locate the right compose
|
|
30
|
+
file(s), including:
|
|
31
|
+
|
|
32
|
+
- **Single file** (string): `"dockerComposeFile": "docker-compose.yml"`
|
|
33
|
+
- **Multiple files** (array): `"dockerComposeFile": ["base.yml", "override.yml"]`
|
|
34
|
+
- **Relative paths** pointing outside the `.devcontainer/` directory:
|
|
35
|
+
`"dockerComposeFile": "../docker-compose.yml"`
|
|
36
|
+
|
|
37
|
+
All referenced compose files are analysed. Every service with a recognised
|
|
38
|
+
image (postgres, redis, grafana, jaeger, …) is mapped to the corresponding
|
|
39
|
+
overlay. Services with no overlay equivalent are written to
|
|
40
|
+
`custom/docker-compose.patch.yml` so they are preserved across regenerations.
|
|
41
|
+
|
|
42
|
+
## How It Works
|
|
43
|
+
|
|
44
|
+
### Detection
|
|
45
|
+
|
|
46
|
+
The command builds its detection tables **dynamically from the overlay registry** — there are no hardcoded overlay names. For every overlay it reads:
|
|
47
|
+
|
|
48
|
+
| Source | What is extracted |
|
|
49
|
+
| -------------------------------------------------------------- | ------------------------- |
|
|
50
|
+
| `devcontainer.patch.json` → `features` | Feature URI → overlay ID |
|
|
51
|
+
| `devcontainer.patch.json` → `customizations.vscode.extensions` | Extension ID → overlay ID |
|
|
52
|
+
| `docker-compose.yml` → service `image` | Image prefix → overlay ID |
|
|
53
|
+
|
|
54
|
+
When multiple overlays share the same feature (e.g. both `nodejs` and `bun`
|
|
55
|
+
include the Node.js devcontainer feature), the one whose ID best matches the
|
|
56
|
+
feature's own name wins.
|
|
57
|
+
|
|
58
|
+
### Detection signals (in priority order)
|
|
59
|
+
|
|
60
|
+
1. **Devcontainer features** — e.g. `ghcr.io/devcontainers/features/node:1` → `nodejs` (confidence: **exact**)
|
|
61
|
+
2. **Docker Compose service images** — e.g. `postgres:16-alpine` → `postgres` (confidence: **exact**)
|
|
62
|
+
3. **VS Code extensions** — e.g. `ms-python.python` → `python` (confidence: **heuristic**)
|
|
63
|
+
4. **Remote environment variables** — e.g. `POSTGRES_*` → `postgres` (confidence: **heuristic**)
|
|
64
|
+
|
|
65
|
+
### Unmatched items → `custom/`
|
|
66
|
+
|
|
67
|
+
Anything that cannot be mapped to an overlay is preserved in the `custom/`
|
|
68
|
+
directory, which is merged automatically on every `regen`:
|
|
69
|
+
|
|
70
|
+
| Unmatched item | Written to |
|
|
71
|
+
| ----------------------------------------------- | --------------------------------------------------------------------- |
|
|
72
|
+
| Unknown features | `custom/devcontainer.patch.json` → `features` |
|
|
73
|
+
| Unknown VS Code extensions | `custom/devcontainer.patch.json` → `customizations.vscode.extensions` |
|
|
74
|
+
| Custom `mounts` | `custom/devcontainer.patch.json` → `mounts` |
|
|
75
|
+
| Non-default `remoteUser` | `custom/devcontainer.patch.json` → `remoteUser` |
|
|
76
|
+
| Custom `postCreateCommand` / `postStartCommand` | `custom/devcontainer.patch.json` |
|
|
77
|
+
| Unknown compose services | `custom/docker-compose.patch.yml` → `services` |
|
|
78
|
+
|
|
79
|
+
## Backup Behaviour
|
|
80
|
+
|
|
81
|
+
The same backup logic as `regen` is used:
|
|
82
|
+
|
|
83
|
+
| Condition | What happens |
|
|
84
|
+
| ---------------------------- | ------------------------------ |
|
|
85
|
+
| Inside a git repo (default) | No backup — git tracks history |
|
|
86
|
+
| Outside a git repo (default) | Backup created automatically |
|
|
87
|
+
| `--backup` flag | Backup always created |
|
|
88
|
+
| `--no-backup` flag | Backup always skipped |
|
|
89
|
+
|
|
90
|
+
Backups are placed next to the `.devcontainer/` directory as
|
|
91
|
+
`.devcontainer.backup-<timestamp>/`, and the corresponding glob patterns are
|
|
92
|
+
automatically added to `.gitignore`.
|
|
93
|
+
|
|
94
|
+
## Options
|
|
95
|
+
|
|
96
|
+
| Option | Description |
|
|
97
|
+
| --------------------- | ---------------------------------------------------------------------------- |
|
|
98
|
+
| `-d, --dir <path>` | Path to the existing `.devcontainer/` directory (default: `./.devcontainer`) |
|
|
99
|
+
| `--dry-run` | Print the analysis without writing any files |
|
|
100
|
+
| `--force` | Overwrite existing `superposition.json` / `custom/` files |
|
|
101
|
+
| `--backup` | Force a backup even when inside a git repo |
|
|
102
|
+
| `--no-backup` | Disable backup creation even when it would normally be performed |
|
|
103
|
+
| `--backup-dir <path>` | Custom backup directory location |
|
|
104
|
+
| `--json` | Output analysis as JSON (useful for scripting) |
|
|
105
|
+
|
|
106
|
+
## Example Output
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
╭──────────────────────╮
|
|
110
|
+
│ 🔍 Adopt Analysis │
|
|
111
|
+
╰──────────────────────╯
|
|
112
|
+
|
|
113
|
+
Analysing .devcontainer/devcontainer.json...
|
|
114
|
+
Analysing .devcontainer/docker-compose.yml...
|
|
115
|
+
|
|
116
|
+
Detected features / services → suggested overlays
|
|
117
|
+
────────────────────────────────────────────────────────────────────────────────
|
|
118
|
+
Source → Overlay Confidence
|
|
119
|
+
────────────────────────────────────────────────────────────────────────────────────────────────
|
|
120
|
+
ghcr.io/devcontainers/features/node:1 → nodejs exact
|
|
121
|
+
service: postgres (image: postgres:16-alpine) → postgres exact
|
|
122
|
+
service: redis (image: redis:7-alpine) → redis exact
|
|
123
|
+
|
|
124
|
+
Items with no overlay equivalent → custom/
|
|
125
|
+
────────────────────────────────────────────────────────────────────────────────
|
|
126
|
+
Source Action
|
|
127
|
+
────────────────────────────────────────────────────────────────────────────────────────────────
|
|
128
|
+
ghcr.io/corp/internal-tools:1 No overlay covers this feature — preserve in custom/devcontainer.patch.json
|
|
129
|
+
service: my-app (image: my-registry/my-app:latest) No overlay covers this service — preserve in custom/docker-compose.patch.yml
|
|
130
|
+
|
|
131
|
+
Suggested command:
|
|
132
|
+
container-superposition init --stack compose --language nodejs --database postgres,redis
|
|
133
|
+
|
|
134
|
+
💡 Custom patches will be written to .devcontainer/custom/ to preserve
|
|
135
|
+
any configuration that has no overlay equivalent.
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## After Adopt
|
|
139
|
+
|
|
140
|
+
Once `adopt` has run:
|
|
141
|
+
|
|
142
|
+
1. **Review `superposition.json`** — verify the detected overlays are correct; add or remove as needed.
|
|
143
|
+
2. **Review `custom/` patches** — inspect what was preserved and trim anything no longer needed.
|
|
144
|
+
3. **Regenerate** — rebuild your `.devcontainer/` from the manifest:
|
|
145
|
+
```bash
|
|
146
|
+
npx container-superposition regen
|
|
147
|
+
```
|
|
148
|
+
4. **Commit `superposition.json`** and, if applicable, `custom/` patches.
|
|
149
|
+
|
|
150
|
+
## JSON Output
|
|
151
|
+
|
|
152
|
+
Use `--json` to get machine-readable output for scripting or CI workflows:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
npx container-superposition adopt --dry-run --json | jq .suggestedOverlays
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The JSON object contains:
|
|
159
|
+
|
|
160
|
+
```jsonc
|
|
161
|
+
{
|
|
162
|
+
"dir": "/absolute/path/to/.devcontainer",
|
|
163
|
+
"detections": [
|
|
164
|
+
{
|
|
165
|
+
"source": "ghcr.io/devcontainers/features/node:1",
|
|
166
|
+
"overlayId": "nodejs",
|
|
167
|
+
"confidence": "exact",
|
|
168
|
+
"sourceType": "feature",
|
|
169
|
+
},
|
|
170
|
+
// ...
|
|
171
|
+
],
|
|
172
|
+
"unmatchedItems": [
|
|
173
|
+
{
|
|
174
|
+
"source": "ghcr.io/corp/internal-tools:1",
|
|
175
|
+
"reason": "No overlay covers this feature — preserve in custom/devcontainer.patch.json",
|
|
176
|
+
},
|
|
177
|
+
// ...
|
|
178
|
+
],
|
|
179
|
+
"customDevcontainerPatch": {
|
|
180
|
+
/* or null */
|
|
181
|
+
},
|
|
182
|
+
"customComposePatch": {
|
|
183
|
+
/* or null */
|
|
184
|
+
},
|
|
185
|
+
"suggestedStack": "compose",
|
|
186
|
+
"suggestedOverlays": ["nodejs", "postgres", "redis"],
|
|
187
|
+
"suggestedCommand": "container-superposition init --stack compose --language nodejs --database postgres,redis",
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## See Also
|
|
192
|
+
|
|
193
|
+
- [Team Workflow](team-workflow.md) — Manifest-first team collaboration workflow
|
|
194
|
+
- [Custom Patches](custom-patches.md) — How `custom/` patches are merged
|
|
195
|
+
- [Workflows and Regeneration](workflows.md) — Regeneration and backup details
|
|
196
|
+
- [Quick Reference](quick-reference.md) — All commands at a glance
|
package/docs/custom-patches.md
CHANGED
|
@@ -223,6 +223,9 @@ The `plan` command shows a dry-run preview of what will be generated, including
|
|
|
223
223
|
```bash
|
|
224
224
|
# Preview generation for postgres and grafana
|
|
225
225
|
npx container-superposition plan --stack compose --overlays postgres,grafana
|
|
226
|
+
|
|
227
|
+
# Preview generation from an existing manifest
|
|
228
|
+
npx container-superposition plan --from-manifest .devcontainer/superposition.json
|
|
226
229
|
```
|
|
227
230
|
|
|
228
231
|
**Output:**
|
|
@@ -265,12 +268,18 @@ Files to Create/Modify:
|
|
|
265
268
|
|
|
266
269
|
### Required Options
|
|
267
270
|
|
|
268
|
-
- `--stack <type>` - Base template: `plain` or `compose`
|
|
271
|
+
- `--stack <type>` - Base template: `plain` or `compose` when planning from explicit overlays
|
|
269
272
|
- `--overlays <list>` - Comma-separated list of overlay IDs
|
|
270
273
|
|
|
274
|
+
### Manifest Input
|
|
275
|
+
|
|
276
|
+
- `--from-manifest <path>` - Load stack and overlay roots from an existing `superposition.json`
|
|
277
|
+
- Use either `--overlays` or `--from-manifest` for a given `plan` invocation
|
|
278
|
+
|
|
271
279
|
### Optional Options
|
|
272
280
|
|
|
273
281
|
- `--port-offset <number>` - Add offset to all exposed ports
|
|
282
|
+
- `--verbose` - Explain why each overlay was included in the resolved plan
|
|
274
283
|
- `--json` - Output as JSON
|
|
275
284
|
|
|
276
285
|
### Port Offset Example
|
|
@@ -308,6 +317,35 @@ Auto-Added Dependencies:
|
|
|
308
317
|
+ prometheus (Prometheus)
|
|
309
318
|
```
|
|
310
319
|
|
|
320
|
+
### Verbose Dependency Narration
|
|
321
|
+
|
|
322
|
+
Add `--verbose` when you want the plan to explain why each overlay appears in the final result:
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
npx container-superposition plan --stack compose --overlays grafana --verbose
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
**Additional output:**
|
|
329
|
+
|
|
330
|
+
```text
|
|
331
|
+
Dependency Resolution:
|
|
332
|
+
grafana (Grafana)
|
|
333
|
+
- selected directly by the user
|
|
334
|
+
prometheus (Prometheus)
|
|
335
|
+
- required by grafana
|
|
336
|
+
- path: grafana -> prometheus
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
This keeps the standard summary intact and adds the reasoning behind direct selections, auto-added dependencies, and failure notes when resolution cannot complete cleanly.
|
|
340
|
+
|
|
341
|
+
The same verbose explanation works for existing manifests:
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
npx container-superposition plan --from-manifest .devcontainer/superposition.json --verbose
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
In manifest mode, overlays loaded from `superposition.json` are treated as the explicit root set and auto-added dependencies are still explained separately.
|
|
348
|
+
|
|
311
349
|
### Conflict Detection
|
|
312
350
|
|
|
313
351
|
The `plan` command detects conflicts before generation:
|
|
@@ -334,6 +372,12 @@ npx container-superposition plan --stack compose --overlays docker-in-docker,doc
|
|
|
334
372
|
```bash
|
|
335
373
|
# Get plan as JSON
|
|
336
374
|
npx container-superposition plan --stack compose --overlays postgres --json
|
|
375
|
+
|
|
376
|
+
# Include structured dependency explanations
|
|
377
|
+
npx container-superposition plan --stack compose --overlays grafana --json --verbose
|
|
378
|
+
|
|
379
|
+
# Include structured dependency explanations from a manifest
|
|
380
|
+
npx container-superposition plan --from-manifest .devcontainer/superposition.json --json --verbose
|
|
337
381
|
```
|
|
338
382
|
|
|
339
383
|
**Example output:**
|
|
@@ -357,11 +401,19 @@ npx container-superposition plan --stack compose --overlays postgres --json
|
|
|
357
401
|
".devcontainer/docker-compose.yml",
|
|
358
402
|
".devcontainer/.env.example",
|
|
359
403
|
".devcontainer/README.md"
|
|
360
|
-
]
|
|
361
|
-
"portOffset": 0
|
|
404
|
+
]
|
|
362
405
|
}
|
|
363
406
|
```
|
|
364
407
|
|
|
408
|
+
When `--verbose` is also present, the JSON output includes a `verbose` object with:
|
|
409
|
+
|
|
410
|
+
- one entry per included overlay
|
|
411
|
+
- direct-vs-dependency selection type
|
|
412
|
+
- input mode metadata for overlay-list vs manifest planning
|
|
413
|
+
- parent reasons for inclusion
|
|
414
|
+
- ordered dependency paths for transitive inclusions
|
|
415
|
+
- resolution notes for skipped overlays or conflicts
|
|
416
|
+
|
|
365
417
|
## Scripting Examples
|
|
366
418
|
|
|
367
419
|
### Export All Overlays to JSON
|