container-superposition 0.1.7 → 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 -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/doctor.d.ts.map +1 -1
- package/dist/tool/commands/doctor.js +141 -6
- 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 +3 -3
- package/dist/tool/questionnaire/composer.d.ts.map +1 -1
- package/dist/tool/questionnaire/composer.js +691 -27
- 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 +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 +183 -9
- 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 +38 -1
- 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 +113 -28
- 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 +27 -2
- package/overlays/.shared/compose/nvidia-gpu-devcontainer.yml +22 -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/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/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/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/postgres/.env.example +5 -5
- package/overlays/postgres/devcontainer.patch.json +4 -4
- package/overlays/postgres/docker-compose.yml +10 -6
- package/overlays/postgres/overlay.yml +19 -1
- 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/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/package.json +3 -2
- package/tool/schema/config.schema.json +31 -1
- package/tool/schema/overlay-manifest.schema.json +33 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import boxen from 'boxen';
|
|
5
|
+
import ora from 'ora';
|
|
6
|
+
import { composeDevContainer, generateManifestOnly } from '../questionnaire/composer.js';
|
|
7
|
+
import { loadManifest } from '../schema/manifest-migrations.js';
|
|
8
|
+
import { printSummary } from '../utils/summary.js';
|
|
9
|
+
import { buildAnswersFromManifest, buildAnswersFromProjectConfig, buildProjectConfigSelectionFromAnswers, findManifestFile, findDefaultRegenManifest, findProjectConfig, loadProjectConfig, writeProjectConfig, writeProjectConfigCustomizations, } from '../schema/project-config.js';
|
|
10
|
+
import { isInsideGitRepo, createBackup, ensureBackupPatternsInGitignore } from '../utils/backup.js';
|
|
11
|
+
import { buildAnswersFromCliArgs, mergeAnswers } from '../questionnaire/answers.js';
|
|
12
|
+
import { applyPresetSelections } from '../questionnaire/presets.js';
|
|
13
|
+
import { runQuestionnaire, loadOverlaysConfigWrapper, PRESETS_DIR, } from '../questionnaire/questionnaire.js';
|
|
14
|
+
import { parseCliArgs } from './args.js';
|
|
15
|
+
export async function main() {
|
|
16
|
+
try {
|
|
17
|
+
const cliArgs = await parseCliArgs();
|
|
18
|
+
const initialCwd = process.cwd();
|
|
19
|
+
if (cliArgs?.projectRoot) {
|
|
20
|
+
const resolvedProjectRoot = path.resolve(initialCwd, cliArgs.projectRoot);
|
|
21
|
+
if (!fs.existsSync(resolvedProjectRoot)) {
|
|
22
|
+
console.error(chalk.red(`✗ Project root not found: ${resolvedProjectRoot}`));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
if (!fs.statSync(resolvedProjectRoot).isDirectory()) {
|
|
26
|
+
console.error(chalk.red(`✗ Project root is not a directory: ${resolvedProjectRoot}`));
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
process.chdir(resolvedProjectRoot);
|
|
30
|
+
}
|
|
31
|
+
let projectFileOutputPath;
|
|
32
|
+
let existingProjectFileDetected = false;
|
|
33
|
+
if (cliArgs?.commandName === 'init' || cliArgs?.commandName === undefined) {
|
|
34
|
+
const discoveredProjectFiles = findProjectConfig(process.cwd());
|
|
35
|
+
if (discoveredProjectFiles.length > 1) {
|
|
36
|
+
console.error(chalk.red('✗ Found both .superposition.yml and superposition.yml in the repository root. Keep only one.'));
|
|
37
|
+
console.error(chalk.gray(' Recommended: keep .superposition.yml (dotfile) to keep the root tidy; delete superposition.yml.'));
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
if (discoveredProjectFiles.length === 1) {
|
|
41
|
+
existingProjectFileDetected = true;
|
|
42
|
+
}
|
|
43
|
+
projectFileOutputPath =
|
|
44
|
+
discoveredProjectFiles[0]?.path ?? path.join(process.cwd(), '.superposition.yml');
|
|
45
|
+
}
|
|
46
|
+
let projectConfig = undefined;
|
|
47
|
+
let projectConfigAnswers;
|
|
48
|
+
if (!cliArgs?.manifestPath) {
|
|
49
|
+
const overlaysConfigForProject = loadOverlaysConfigWrapper();
|
|
50
|
+
projectConfig = loadProjectConfig(overlaysConfigForProject, process.cwd()) ?? undefined;
|
|
51
|
+
if (projectConfig) {
|
|
52
|
+
projectConfigAnswers = await applyPresetSelections(buildAnswersFromProjectConfig(projectConfig.selection, overlaysConfigForProject), overlaysConfigForProject, PRESETS_DIR);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
let manifest;
|
|
56
|
+
let manifestDir;
|
|
57
|
+
let backupDir;
|
|
58
|
+
let useManifestOnly = false;
|
|
59
|
+
let useProjectOnly = false;
|
|
60
|
+
if (cliArgs?.commandName === 'regen' && !cliArgs.manifestPath && !cliArgs.fromProject) {
|
|
61
|
+
if (projectConfigAnswers) {
|
|
62
|
+
useProjectOnly = true;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
const discoveredManifestPath = findDefaultRegenManifest(cliArgs?.config?.outputPath || './.devcontainer');
|
|
66
|
+
if (discoveredManifestPath) {
|
|
67
|
+
console.error(chalk.red('✗ Error: No project file found'));
|
|
68
|
+
console.error(chalk.cyan(' Found superposition.json but no superposition.yml project file.'));
|
|
69
|
+
console.error(chalk.gray(' Run `cs migrate` to create a project file from your existing manifest, then run `regen` again.'));
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
console.error(chalk.red('✗ Error: No project file found'));
|
|
73
|
+
console.error(chalk.gray(' Create .superposition.yml or superposition.yml in your repository root.'));
|
|
74
|
+
console.error(chalk.dim(' Or run `cs init` to create a new configuration interactively.'));
|
|
75
|
+
}
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (cliArgs?.commandName === 'regen' && cliArgs?.manifestPath) {
|
|
80
|
+
console.warn(chalk.yellow('⚠️ --from-manifest is deprecated for regen. Run `cs migrate` to create a project file, then use `regen` without this flag.'));
|
|
81
|
+
}
|
|
82
|
+
if (cliArgs?.manifestPath) {
|
|
83
|
+
const manifestPath = findManifestFile(cliArgs.manifestPath);
|
|
84
|
+
if (!manifestPath) {
|
|
85
|
+
console.error(chalk.red('✗ Could not find manifest file'));
|
|
86
|
+
console.error(chalk.red(` Searched for: ${cliArgs.manifestPath}`));
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
manifestDir = path.dirname(manifestPath);
|
|
90
|
+
const loadedManifest = loadManifest(manifestPath);
|
|
91
|
+
if (!loadedManifest) {
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
manifest = loadedManifest;
|
|
95
|
+
if (cliArgs.backupDir) {
|
|
96
|
+
backupDir = cliArgs.backupDir;
|
|
97
|
+
}
|
|
98
|
+
if (cliArgs.noInteractive) {
|
|
99
|
+
useManifestOnly = true;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (cliArgs?.fromProject) {
|
|
103
|
+
if (!projectConfigAnswers || !projectConfig) {
|
|
104
|
+
console.error(chalk.red('✗ Could not find project file'));
|
|
105
|
+
console.error(chalk.red(' Searched for: .superposition.yml, superposition.yml'));
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
useProjectOnly = cliArgs.noInteractive || cliArgs.commandName === 'regen';
|
|
109
|
+
}
|
|
110
|
+
if (cliArgs?.noInteractive && !cliArgs?.manifestPath && !projectConfigAnswers) {
|
|
111
|
+
console.error(chalk.red('✗ Error: --no-interactive requires persisted input'));
|
|
112
|
+
console.error(chalk.dim(' Use --from-project or run from a repository with .superposition.yml or superposition.yml'));
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
const resolvedOutputPath = cliArgs?.config?.outputPath ||
|
|
116
|
+
projectConfigAnswers?.outputPath ||
|
|
117
|
+
manifestDir ||
|
|
118
|
+
'./.devcontainer';
|
|
119
|
+
const backupCheckPath = path.resolve(resolvedOutputPath);
|
|
120
|
+
const inGitRepo = isInsideGitRepo(backupCheckPath);
|
|
121
|
+
let shouldBackup;
|
|
122
|
+
if (cliArgs?.backupOverride === true) {
|
|
123
|
+
shouldBackup = true;
|
|
124
|
+
}
|
|
125
|
+
else if (cliArgs?.backupOverride === false) {
|
|
126
|
+
shouldBackup = false;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
shouldBackup = !inGitRepo;
|
|
130
|
+
if (!shouldBackup) {
|
|
131
|
+
console.log(chalk.dim('ℹ Skipping backup — git repo detected (use --backup to force one)\n'));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const isReplayMode = cliArgs?.commandName === 'regen' || useManifestOnly || useProjectOnly;
|
|
135
|
+
let actualBackupPath;
|
|
136
|
+
if (shouldBackup && isReplayMode) {
|
|
137
|
+
const outputPath = resolvedOutputPath;
|
|
138
|
+
const backupPath = await createBackup(outputPath, backupDir);
|
|
139
|
+
if (backupPath) {
|
|
140
|
+
actualBackupPath = backupPath;
|
|
141
|
+
console.log(chalk.green(`✓ Backup created: ${backupPath}\n`));
|
|
142
|
+
ensureBackupPatternsInGitignore(outputPath);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const mainOverlaysConfig = loadOverlaysConfigWrapper();
|
|
146
|
+
let answers;
|
|
147
|
+
const hasCliOverrides = cliArgs &&
|
|
148
|
+
Object.keys(cliArgs.config).some((key) => key !== 'outputPath' &&
|
|
149
|
+
key !== 'preset' &&
|
|
150
|
+
key !== 'presetChoices' &&
|
|
151
|
+
!(key === 'target' && cliArgs.config.target === 'local') &&
|
|
152
|
+
!(key === 'editor' && cliArgs.config.editor === 'vscode') &&
|
|
153
|
+
cliArgs.config[key] !== undefined);
|
|
154
|
+
const hasAnyCliConfig = cliArgs &&
|
|
155
|
+
Object.entries(cliArgs.config).some(([key, value]) => value !== undefined &&
|
|
156
|
+
!(key === 'target' && value === 'local') &&
|
|
157
|
+
!(key === 'editor' && value === 'vscode'));
|
|
158
|
+
if (useManifestOnly && manifest && !hasCliOverrides) {
|
|
159
|
+
const manifestAnswers = buildAnswersFromManifest(manifest, mainOverlaysConfig, manifestDir);
|
|
160
|
+
answers = mergeAnswers(manifestAnswers);
|
|
161
|
+
console.log('\n' +
|
|
162
|
+
boxen(chalk.bold.cyan('Regenerating from Manifest (No Interactive)\n\n') +
|
|
163
|
+
chalk.white('Configuration:\n') +
|
|
164
|
+
chalk.gray(` Template: ${manifest.baseTemplate}\n`) +
|
|
165
|
+
chalk.gray(` Base Image: ${manifest.baseImage}\n`) +
|
|
166
|
+
(manifest.containerName
|
|
167
|
+
? chalk.gray(` Container: ${manifest.containerName}\n`)
|
|
168
|
+
: '') +
|
|
169
|
+
chalk.gray(` Overlays: ${manifest.overlays.join(', ')}\n`) +
|
|
170
|
+
(manifest.preset ? chalk.gray(` Preset: ${manifest.preset}\n`) : '') +
|
|
171
|
+
(manifest.portOffset
|
|
172
|
+
? chalk.gray(` Port offset: ${manifest.portOffset}\n`)
|
|
173
|
+
: '') +
|
|
174
|
+
chalk.gray(` Output: ${answers.outputPath}`), { padding: 1, borderColor: 'cyan', borderStyle: 'round', margin: 1 }));
|
|
175
|
+
}
|
|
176
|
+
else if (useProjectOnly && projectConfigAnswers && !hasCliOverrides) {
|
|
177
|
+
const projectFileName = projectConfig?.file.fileName ?? '.superposition.yml';
|
|
178
|
+
answers = mergeAnswers(projectConfigAnswers, {
|
|
179
|
+
outputPath: cliArgs?.config?.outputPath ||
|
|
180
|
+
projectConfigAnswers.outputPath ||
|
|
181
|
+
'./.devcontainer',
|
|
182
|
+
minimal: cliArgs?.config?.minimal,
|
|
183
|
+
editor: cliArgs?.config?.editor,
|
|
184
|
+
});
|
|
185
|
+
console.log('\n' +
|
|
186
|
+
boxen(chalk.bold.cyan('Regenerating from Project File (No Interactive)\n\n') +
|
|
187
|
+
chalk.white('Configuration:\n') +
|
|
188
|
+
chalk.gray(` Project file: ${projectFileName}\n`) +
|
|
189
|
+
chalk.gray(` Output: ${answers.outputPath}`), {
|
|
190
|
+
padding: 1,
|
|
191
|
+
borderColor: 'cyan',
|
|
192
|
+
borderStyle: 'round',
|
|
193
|
+
margin: 1,
|
|
194
|
+
}));
|
|
195
|
+
}
|
|
196
|
+
else if ((cliArgs && (cliArgs.config.stack || hasCliOverrides)) ||
|
|
197
|
+
(projectConfigAnswers && (cliArgs?.noInteractive || hasAnyCliConfig))) {
|
|
198
|
+
const cliAnswers = buildAnswersFromCliArgs(cliArgs.config);
|
|
199
|
+
const manifestAnswers = manifest
|
|
200
|
+
? buildAnswersFromManifest(manifest, mainOverlaysConfig, manifestDir)
|
|
201
|
+
: undefined;
|
|
202
|
+
answers = mergeAnswers(projectConfigAnswers, manifestAnswers, cliAnswers, {
|
|
203
|
+
outputPath: cliAnswers.outputPath || projectConfigAnswers?.outputPath || './.devcontainer',
|
|
204
|
+
});
|
|
205
|
+
const modeLabel = useManifestOnly && hasCliOverrides
|
|
206
|
+
? 'Regenerating from Manifest with Overrides'
|
|
207
|
+
: useProjectOnly && projectConfigAnswers
|
|
208
|
+
? 'Regenerating from Project File with Overrides'
|
|
209
|
+
: projectConfigAnswers && !manifest
|
|
210
|
+
? 'Running from Project Config'
|
|
211
|
+
: 'Running in CLI mode';
|
|
212
|
+
console.log('\n' +
|
|
213
|
+
boxen(chalk.bold(modeLabel), {
|
|
214
|
+
padding: 0.5,
|
|
215
|
+
borderColor: 'blue',
|
|
216
|
+
borderStyle: 'round',
|
|
217
|
+
}));
|
|
218
|
+
if ((useManifestOnly || useProjectOnly) && hasCliOverrides) {
|
|
219
|
+
const overrides = [];
|
|
220
|
+
if (cliAnswers.minimal)
|
|
221
|
+
overrides.push('minimal mode');
|
|
222
|
+
if (cliAnswers.editor)
|
|
223
|
+
overrides.push(`editor: ${cliAnswers.editor}`);
|
|
224
|
+
if (overrides.length > 0) {
|
|
225
|
+
console.log(chalk.dim(` Overrides: ${overrides.join(', ')}`));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
const interactiveAnswers = await runQuestionnaire(manifest, manifestDir, cliArgs?.config.preset || projectConfigAnswers?.preset, cliArgs?.config.presetChoices || projectConfigAnswers?.presetChoices, projectConfigAnswers);
|
|
231
|
+
answers = mergeAnswers(projectConfigAnswers, interactiveAnswers);
|
|
232
|
+
}
|
|
233
|
+
if (!manifest && projectConfig?.selection.customizations) {
|
|
234
|
+
const materializedOutputPath = path.resolve(answers.outputPath);
|
|
235
|
+
if (!fs.existsSync(materializedOutputPath)) {
|
|
236
|
+
fs.mkdirSync(materializedOutputPath, { recursive: true });
|
|
237
|
+
}
|
|
238
|
+
writeProjectConfigCustomizations(materializedOutputPath, projectConfig.selection.customizations);
|
|
239
|
+
}
|
|
240
|
+
const summaryLines = [
|
|
241
|
+
chalk.bold.white('Configuration Summary\n'),
|
|
242
|
+
chalk.cyan('Base: ') + chalk.white(answers.stack),
|
|
243
|
+
];
|
|
244
|
+
if (answers.language && answers.language.length > 0) {
|
|
245
|
+
summaryLines.push(chalk.cyan('Languages: ') + chalk.white(answers.language.join(', ')));
|
|
246
|
+
}
|
|
247
|
+
if (answers.database && answers.database.length > 0) {
|
|
248
|
+
summaryLines.push(chalk.cyan('Database: ') + chalk.white(answers.database.join(', ')));
|
|
249
|
+
}
|
|
250
|
+
summaryLines.push(chalk.cyan('Playwright: ') + chalk.white(answers.playwright ? 'Yes' : 'No'));
|
|
251
|
+
if (answers.observability && answers.observability.length > 0) {
|
|
252
|
+
summaryLines.push(chalk.cyan('Observability: ') + chalk.white(answers.observability.join(', ')));
|
|
253
|
+
}
|
|
254
|
+
if (answers.cloudTools && answers.cloudTools.length > 0) {
|
|
255
|
+
summaryLines.push(chalk.cyan('Cloud tools: ') + chalk.white(answers.cloudTools.join(', ')));
|
|
256
|
+
}
|
|
257
|
+
if (projectConfig?.file && !manifest) {
|
|
258
|
+
summaryLines.push(chalk.cyan('Project config: ') + chalk.white(projectConfig.file.fileName));
|
|
259
|
+
}
|
|
260
|
+
summaryLines.push(chalk.cyan('Output: ') + chalk.white(answers.outputPath));
|
|
261
|
+
console.log('\n' +
|
|
262
|
+
boxen(summaryLines.join('\n'), {
|
|
263
|
+
padding: 1,
|
|
264
|
+
borderColor: 'green',
|
|
265
|
+
borderStyle: 'round',
|
|
266
|
+
margin: { top: 0, bottom: 1 },
|
|
267
|
+
}));
|
|
268
|
+
if (existingProjectFileDetected && projectFileOutputPath) {
|
|
269
|
+
const relPath = path.relative(process.cwd(), projectFileOutputPath);
|
|
270
|
+
console.log(chalk.yellow(`⚠ Existing project file will be updated: ${relPath}\n Run \`cs regen\` instead to replay the existing configuration without changes.`));
|
|
271
|
+
}
|
|
272
|
+
if (projectFileOutputPath) {
|
|
273
|
+
try {
|
|
274
|
+
const projectSelection = buildProjectConfigSelectionFromAnswers(answers);
|
|
275
|
+
writeProjectConfig(projectFileOutputPath, projectSelection);
|
|
276
|
+
console.log(chalk.green(`✓ Project config written: ${path.relative(process.cwd(), projectFileOutputPath)}`));
|
|
277
|
+
}
|
|
278
|
+
catch (projectFileError) {
|
|
279
|
+
console.error(chalk.yellow(`⚠ Failed to write project config: ${projectFileError instanceof Error ? projectFileError.message : String(projectFileError)}`));
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
const isManifestOnly = cliArgs?.writeManifestOnly === true || cliArgs?.noScaffold === true;
|
|
283
|
+
const spinner = ora({
|
|
284
|
+
text: isManifestOnly
|
|
285
|
+
? chalk.cyan('Generating manifest file...')
|
|
286
|
+
: chalk.cyan('Generating devcontainer configuration...'),
|
|
287
|
+
color: 'cyan',
|
|
288
|
+
}).start();
|
|
289
|
+
try {
|
|
290
|
+
let summary;
|
|
291
|
+
if (isManifestOnly) {
|
|
292
|
+
summary = await generateManifestOnly(answers, undefined, {
|
|
293
|
+
isRegen: isReplayMode,
|
|
294
|
+
});
|
|
295
|
+
spinner.succeed(chalk.green('Manifest created successfully!'));
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
summary = await composeDevContainer(answers, undefined, { isRegen: isReplayMode });
|
|
299
|
+
spinner.succeed(chalk.green('DevContainer created successfully!'));
|
|
300
|
+
}
|
|
301
|
+
if (actualBackupPath) {
|
|
302
|
+
summary.backupPath = actualBackupPath;
|
|
303
|
+
}
|
|
304
|
+
printSummary(summary);
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
spinner.fail(chalk.red(isManifestOnly ? 'Failed to create manifest' : 'Failed to create devcontainer'));
|
|
308
|
+
throw error;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
catch (error) {
|
|
312
|
+
console.error('\n' +
|
|
313
|
+
boxen(chalk.bold.red('Error\n\n') +
|
|
314
|
+
chalk.white(error instanceof Error ? error.message : String(error)), { padding: 1, borderColor: 'red', borderStyle: 'round' }));
|
|
315
|
+
process.exit(1);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../tool/cli/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../tool/commands/doctor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,KAAK,EACR,cAAc,EAmBjB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../tool/commands/doctor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,KAAK,EACR,cAAc,EAmBjB,MAAM,oBAAoB,CAAC;AAe5B,UAAU,aAAa;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB;AAq7DD;;GAEG;AACH,wBAAsB,aAAa,CAC/B,cAAc,EAAE,cAAc,EAC9B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,aAAa,GACvB,OAAO,CAAC,IAAI,CAAC,CA6Jf"}
|
|
@@ -12,6 +12,7 @@ import { detectManifestVersion, isVersionSupported, needsMigration, migrateManif
|
|
|
12
12
|
import { MERGE_STRATEGY } from '../utils/merge.js';
|
|
13
13
|
import { extractPorts } from '../utils/port-utils.js';
|
|
14
14
|
import { composeDevContainer } from '../questionnaire/composer.js';
|
|
15
|
+
import { mergeAnswers } from '../questionnaire/answers.js';
|
|
15
16
|
import { loadProjectConfig } from '../schema/project-config.js';
|
|
16
17
|
// ─── Remediation registry ─────────────────────────────────────────────────
|
|
17
18
|
const REMEDIATION_REGISTRY = new Map([
|
|
@@ -418,6 +419,52 @@ function validateOverlayManifest(overlayDir, overlayId) {
|
|
|
418
419
|
};
|
|
419
420
|
}
|
|
420
421
|
}
|
|
422
|
+
// Validate compose_imports if present
|
|
423
|
+
if (manifest.compose_imports && manifest.compose_imports.length > 0) {
|
|
424
|
+
const overlaysDir = path.dirname(overlayDir);
|
|
425
|
+
const sharedBase = path.resolve(overlaysDir, '.shared');
|
|
426
|
+
const missingImports = [];
|
|
427
|
+
const invalidImports = [];
|
|
428
|
+
const traversalImports = [];
|
|
429
|
+
for (const importPath of manifest.compose_imports) {
|
|
430
|
+
if (!importPath.startsWith('.shared/')) {
|
|
431
|
+
traversalImports.push(`${importPath} (must begin with '.shared/')`);
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
const resolved = path.resolve(overlaysDir, importPath);
|
|
435
|
+
if (!resolved.startsWith(sharedBase + path.sep) && resolved !== sharedBase) {
|
|
436
|
+
traversalImports.push(`${importPath} (resolves outside '.shared/' directory)`);
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
const fullImportPath = path.join(overlaysDir, importPath);
|
|
440
|
+
if (!fs.existsSync(fullImportPath)) {
|
|
441
|
+
missingImports.push(importPath);
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
const ext = path.extname(importPath).toLowerCase();
|
|
445
|
+
if (!['.yaml', '.yml'].includes(ext)) {
|
|
446
|
+
invalidImports.push(`${importPath} (must be .yml or .yaml for compose_imports)`);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (traversalImports.length > 0 || missingImports.length > 0 || invalidImports.length > 0) {
|
|
450
|
+
const details = [];
|
|
451
|
+
if (traversalImports.length > 0) {
|
|
452
|
+
details.push(`Path traversal rejected: ${traversalImports.join(', ')}`);
|
|
453
|
+
}
|
|
454
|
+
if (missingImports.length > 0) {
|
|
455
|
+
details.push(`Missing compose_imports: ${missingImports.join(', ')}`);
|
|
456
|
+
}
|
|
457
|
+
if (invalidImports.length > 0) {
|
|
458
|
+
details.push(`Invalid compose_imports: ${invalidImports.join(', ')}`);
|
|
459
|
+
}
|
|
460
|
+
return {
|
|
461
|
+
name: `Overlay: ${overlayId}`,
|
|
462
|
+
status: 'warn',
|
|
463
|
+
message: 'compose_import validation issues',
|
|
464
|
+
details,
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
}
|
|
421
468
|
return {
|
|
422
469
|
name: `Overlay: ${overlayId}`,
|
|
423
470
|
status: 'pass',
|
|
@@ -817,15 +864,84 @@ function checkMergeStrategy(outputPath) {
|
|
|
817
864
|
return results;
|
|
818
865
|
}
|
|
819
866
|
/**
|
|
820
|
-
*
|
|
867
|
+
* Check for drift between the project config file and the last generated manifest.
|
|
868
|
+
* Reports a warning when the overlay lists differ so users know to run `regen`.
|
|
821
869
|
*/
|
|
822
|
-
function
|
|
870
|
+
function checkProjectFileDrift(overlaysConfig, workingDir, manifestPath) {
|
|
871
|
+
// Load project config — skip silently if not present
|
|
872
|
+
let projectConfig;
|
|
873
|
+
try {
|
|
874
|
+
projectConfig = loadProjectConfig(overlaysConfig, workingDir);
|
|
875
|
+
}
|
|
876
|
+
catch {
|
|
877
|
+
return [];
|
|
878
|
+
}
|
|
879
|
+
if (!projectConfig) {
|
|
880
|
+
return [];
|
|
881
|
+
}
|
|
882
|
+
// Load manifest — if not present while the project file exists, report it informatively
|
|
883
|
+
if (!fs.existsSync(manifestPath)) {
|
|
884
|
+
return [
|
|
885
|
+
{
|
|
886
|
+
name: 'Project file drift',
|
|
887
|
+
status: 'warn',
|
|
888
|
+
message: 'Project file found but no generated manifest — run `cs regen` to generate',
|
|
889
|
+
fixEligibility: 'not-applicable',
|
|
890
|
+
},
|
|
891
|
+
];
|
|
892
|
+
}
|
|
893
|
+
let manifest;
|
|
894
|
+
try {
|
|
895
|
+
const raw = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
896
|
+
manifest = needsMigration(raw) ? migrateManifest(raw) : raw;
|
|
897
|
+
}
|
|
898
|
+
catch {
|
|
899
|
+
return [];
|
|
900
|
+
}
|
|
901
|
+
// Compare overlay sets (order-independent).
|
|
902
|
+
// Exclude auto-resolved dependencies from the manifest side — the project file only
|
|
903
|
+
// stores user-selected overlays; auto-resolved ones are re-calculated at generation time.
|
|
904
|
+
const autoResolvedAdded = new Set(manifest.autoResolved?.added ?? []);
|
|
905
|
+
const projectOverlays = new Set(projectConfig.selection.overlays ?? []);
|
|
906
|
+
const manifestBaseOverlays = new Set((manifest.overlays ?? []).filter((o) => !autoResolvedAdded.has(o)));
|
|
907
|
+
const inProjectNotManifest = [...projectOverlays].filter((o) => !manifestBaseOverlays.has(o));
|
|
908
|
+
const inManifestNotProject = [...manifestBaseOverlays].filter((o) => !projectOverlays.has(o));
|
|
909
|
+
if (inProjectNotManifest.length === 0 && inManifestNotProject.length === 0) {
|
|
910
|
+
return [
|
|
911
|
+
{
|
|
912
|
+
name: 'Project file drift',
|
|
913
|
+
status: 'pass',
|
|
914
|
+
message: 'Project file and generated manifest are consistent',
|
|
915
|
+
fixEligibility: 'not-applicable',
|
|
916
|
+
},
|
|
917
|
+
];
|
|
918
|
+
}
|
|
919
|
+
const details = [];
|
|
920
|
+
if (inProjectNotManifest.length > 0) {
|
|
921
|
+
details.push(`In project file but not in manifest: ${inProjectNotManifest.join(', ')}`);
|
|
922
|
+
}
|
|
923
|
+
if (inManifestNotProject.length > 0) {
|
|
924
|
+
details.push(`In manifest but not in project file: ${inManifestNotProject.join(', ')}`);
|
|
925
|
+
}
|
|
926
|
+
details.push('Run "cs regen" to regenerate with the current project file configuration');
|
|
927
|
+
return [
|
|
928
|
+
{
|
|
929
|
+
name: 'Project file drift',
|
|
930
|
+
status: 'warn',
|
|
931
|
+
message: 'Project file and generated manifest have diverged',
|
|
932
|
+
details,
|
|
933
|
+
fixEligibility: 'manual-only',
|
|
934
|
+
},
|
|
935
|
+
];
|
|
936
|
+
}
|
|
937
|
+
function generateReport(environmentChecks, overlayChecks, manifestChecks, mergeChecks, portChecks, driftChecks = []) {
|
|
823
938
|
const allChecks = [
|
|
824
939
|
...environmentChecks,
|
|
825
940
|
...overlayChecks,
|
|
826
941
|
...manifestChecks,
|
|
827
942
|
...mergeChecks,
|
|
828
943
|
...portChecks,
|
|
944
|
+
...driftChecks,
|
|
829
945
|
];
|
|
830
946
|
const passed = allChecks.filter((c) => c.status === 'pass').length;
|
|
831
947
|
const warnings = allChecks.filter((c) => c.status === 'warn').length;
|
|
@@ -837,6 +953,7 @@ function generateReport(environmentChecks, overlayChecks, manifestChecks, mergeC
|
|
|
837
953
|
manifest: manifestChecks,
|
|
838
954
|
merge: mergeChecks,
|
|
839
955
|
ports: portChecks,
|
|
956
|
+
drift: driftChecks,
|
|
840
957
|
summary: {
|
|
841
958
|
passed,
|
|
842
959
|
warnings,
|
|
@@ -913,6 +1030,20 @@ function formatAsText(report) {
|
|
|
913
1030
|
lines.push(formatCheckResult(check));
|
|
914
1031
|
}
|
|
915
1032
|
}
|
|
1033
|
+
// Drift section
|
|
1034
|
+
if (report.drift.length > 0) {
|
|
1035
|
+
const failedDrift = report.drift.filter((c) => c.status !== 'pass');
|
|
1036
|
+
if (failedDrift.length > 0) {
|
|
1037
|
+
lines.push(chalk.bold('\nProject File:'));
|
|
1038
|
+
for (const check of failedDrift) {
|
|
1039
|
+
lines.push(formatCheckResult(check));
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
else {
|
|
1043
|
+
lines.push(chalk.bold('\nProject File:'));
|
|
1044
|
+
lines.push(` ${chalk.green('✓')} ${chalk.white('Project file and manifest are consistent')}`);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
916
1047
|
// Summary
|
|
917
1048
|
lines.push(chalk.bold('\nSummary:'));
|
|
918
1049
|
lines.push(` ${chalk.green('✓')} ${report.summary.passed} passed`);
|
|
@@ -960,6 +1091,7 @@ function reportToFindings(report) {
|
|
|
960
1091
|
...checksToFindings(report.manifest, 'manifest', 'manifest'),
|
|
961
1092
|
...checksToFindings(report.merge, 'merge', 'devcontainer'),
|
|
962
1093
|
...checksToFindings(report.ports, 'ports', 'environment'),
|
|
1094
|
+
...checksToFindings(report.drift, 'manifest', 'manifest'),
|
|
963
1095
|
];
|
|
964
1096
|
}
|
|
965
1097
|
/**
|
|
@@ -1202,7 +1334,7 @@ async function executeRegeneration(outputPath, overlaysConfig, overlaysDir, sile
|
|
|
1202
1334
|
rechecked: false,
|
|
1203
1335
|
};
|
|
1204
1336
|
}
|
|
1205
|
-
const answers = buildAnswersFromManifest(manifest, outputPath, overlaysConfig);
|
|
1337
|
+
const answers = mergeAnswers(buildAnswersFromManifest(manifest, outputPath, overlaysConfig));
|
|
1206
1338
|
// Suppress console output during regeneration when in JSON mode
|
|
1207
1339
|
const originalLog = console.log;
|
|
1208
1340
|
if (silent) {
|
|
@@ -1439,7 +1571,7 @@ function determineExitDisposition(summary, finalFindings) {
|
|
|
1439
1571
|
/**
|
|
1440
1572
|
* Run the full fix flow: diagnose → narrate → remediate → re-check → summarise.
|
|
1441
1573
|
*/
|
|
1442
|
-
async function executeFixRun(report, outputPath, overlaysConfig, overlaysDir, requestedJson, explicitManifestPath) {
|
|
1574
|
+
async function executeFixRun(report, outputPath, overlaysConfig, overlaysDir, requestedJson, explicitManifestPath, workingDir = process.cwd()) {
|
|
1443
1575
|
const initialFindings = reportToFindings(report);
|
|
1444
1576
|
// Separate automatic and manual-only fixable findings
|
|
1445
1577
|
const autoFixable = initialFindings.filter((f) => f.fixEligibility === 'automatic' && f.status !== 'pass');
|
|
@@ -1500,12 +1632,14 @@ async function executeFixRun(report, outputPath, overlaysConfig, overlaysDir, re
|
|
|
1500
1632
|
const overlayChecks = checkOverlays(overlaysDir);
|
|
1501
1633
|
const finalManifestPath = explicitManifestPath ?? path.join(outputPath, 'superposition.json');
|
|
1502
1634
|
const portChecks = checkPorts(overlaysConfig, finalManifestPath);
|
|
1635
|
+
const finalDriftChecks = checkProjectFileDrift(overlaysConfig, workingDir, finalManifestPath);
|
|
1503
1636
|
const finalFindings = [
|
|
1504
1637
|
...checksToFindings(envChecks, 'environment', 'environment'),
|
|
1505
1638
|
...checksToFindings(manifestChecks, 'manifest', 'manifest'),
|
|
1506
1639
|
...checksToFindings(mergeChecks, 'merge', 'devcontainer'),
|
|
1507
1640
|
...checksToFindings(overlayChecks, 'overlay', 'full'),
|
|
1508
1641
|
...checksToFindings(portChecks, 'ports', 'environment'),
|
|
1642
|
+
...checksToFindings(finalDriftChecks, 'manifest', 'manifest'),
|
|
1509
1643
|
];
|
|
1510
1644
|
const summary = buildOutcomeSummary(executions);
|
|
1511
1645
|
const exitDisposition = determineExitDisposition(summary, finalFindings);
|
|
@@ -1678,15 +1812,16 @@ export async function doctorCommand(overlaysConfig, overlaysDir, options) {
|
|
|
1678
1812
|
const mergeChecks = checkMergeStrategy(outputPath);
|
|
1679
1813
|
const manifestPath = explicitManifestPath ?? path.join(outputPath, 'superposition.json');
|
|
1680
1814
|
const portChecks = checkPorts(overlaysConfig, manifestPath);
|
|
1815
|
+
const driftChecks = checkProjectFileDrift(overlaysConfig, workingDir, manifestPath);
|
|
1681
1816
|
// Generate report
|
|
1682
|
-
const report = generateReport(environmentChecks, overlayChecks, manifestChecks, mergeChecks, portChecks);
|
|
1817
|
+
const report = generateReport(environmentChecks, overlayChecks, manifestChecks, mergeChecks, portChecks, driftChecks);
|
|
1683
1818
|
if (options.fix) {
|
|
1684
1819
|
// ── Fix flow ──────────────────────────────────────────────────────────
|
|
1685
1820
|
if (!options.json) {
|
|
1686
1821
|
// Print diagnostic findings first (as normal)
|
|
1687
1822
|
console.log(formatAsText(report));
|
|
1688
1823
|
}
|
|
1689
|
-
const fixRun = await executeFixRun(report, outputPath, overlaysConfig, overlaysDir, options.json ?? false, explicitManifestPath);
|
|
1824
|
+
const fixRun = await executeFixRun(report, outputPath, overlaysConfig, overlaysDir, options.json ?? false, explicitManifestPath, workingDir);
|
|
1690
1825
|
if (options.json) {
|
|
1691
1826
|
console.log(JSON.stringify(fixRun, null, 2));
|
|
1692
1827
|
}
|