@msn-control/liftoff 0.1.1

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.
@@ -0,0 +1,228 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { mkdir, mkdtemp, rm } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { readBooleanFlag, readListFlag, readStringFlag } from './args.js';
6
+ import { approvedStack, listRegions, patterns, providers, searchRegions } from './catalogs.js';
7
+ import { artifactPath, assertNewOrEmptyDirectory, resolveTargetRoot, validateGeneratedProject, writeArtifacts } from './file-system.js';
8
+ import { confirmPlan, promptForCreateOptions } from './interactive.js';
9
+ import { buildProjectPlan, formatProjectPlan, loadConfigOptions, mergeOptions, PlanValidationError } from './planner.js';
10
+ import { buildArtifacts } from './templates.js';
11
+ export async function runCommand(parsed, context) {
12
+ try {
13
+ switch (parsed.command) {
14
+ case undefined:
15
+ case 'help':
16
+ case '--help':
17
+ printHelp(context.stdout);
18
+ return 0;
19
+ case 'create':
20
+ return await createCommand(parsed, context);
21
+ case 'plan':
22
+ return await planCommand(parsed, context);
23
+ case 'patterns':
24
+ return patternsCommand(context);
25
+ case 'providers':
26
+ return providersCommand(context);
27
+ case 'regions':
28
+ return regionsCommand(parsed, context);
29
+ case 'validate':
30
+ return await validateCommand(parsed, context);
31
+ case 'doctor':
32
+ return doctorCommand(parsed, context);
33
+ case 'dev':
34
+ return helperCommand(parsed, context, 'docker compose');
35
+ case 'infra':
36
+ return helperCommand(parsed, context, 'tofu');
37
+ default:
38
+ context.stderr.write(`Unknown command: ${parsed.command}\n\n`);
39
+ printHelp(context.stderr);
40
+ return 1;
41
+ }
42
+ }
43
+ catch (error) {
44
+ if (error instanceof PlanValidationError) {
45
+ context.stderr.write(`${error.issues.join('\n')}\n`);
46
+ return 1;
47
+ }
48
+ context.stderr.write(`${error.message}\n`);
49
+ return 1;
50
+ }
51
+ }
52
+ async function createCommand(parsed, context) {
53
+ const initial = await optionsFromParsedArgs(parsed, context.cwd, true);
54
+ const needsPrompts = !initial.yes && hasMissingCreateInputs(initial);
55
+ const options = needsPrompts ? await promptForCreateOptions(initial) : initial;
56
+ const plan = buildProjectPlan(options, { requireProjectName: true });
57
+ const confirmed = await confirmPlan(plan, options.yes);
58
+ if (!confirmed) {
59
+ context.stdout.write('Generation cancelled.\n');
60
+ return 0;
61
+ }
62
+ const targetRoot = resolveTargetRoot(context.cwd, plan.safeProjectName);
63
+ const artifacts = buildArtifacts(plan);
64
+ await writeArtifacts(targetRoot, artifacts);
65
+ const issues = await validateGeneratedProject(targetRoot);
66
+ if (issues.length > 0) {
67
+ context.stderr.write(`Generated project validation failed:\n${issues.join('\n')}\n`);
68
+ return 1;
69
+ }
70
+ context.stdout.write(`Created ${plan.projectName} at ${targetRoot}\n`);
71
+ return 0;
72
+ }
73
+ async function planCommand(parsed, context) {
74
+ const options = await optionsFromParsedArgs(parsed, context.cwd, false);
75
+ const plan = buildProjectPlan(options, { requireProjectName: false });
76
+ const artifacts = buildArtifacts(plan);
77
+ context.stdout.write(`${formatProjectPlan(plan)}\n\nArtifacts (${artifacts.length}):\n`);
78
+ for (const artifact of artifacts) {
79
+ context.stdout.write(`- ${artifact.logicalName}: ${artifact.pathParts.join('/')}\n`);
80
+ }
81
+ return 0;
82
+ }
83
+ function patternsCommand(context) {
84
+ context.stdout.write('Patterns:\n');
85
+ for (const pattern of patterns) {
86
+ context.stdout.write(`- ${pattern.id}: ${pattern.label} [${pattern.scaffoldStatus}]\n`);
87
+ }
88
+ return 0;
89
+ }
90
+ function providersCommand(context) {
91
+ context.stdout.write('Providers:\n');
92
+ for (const provider of providers) {
93
+ context.stdout.write(`- ${provider.id}: ${provider.label} [${provider.status}]\n`);
94
+ }
95
+ return 0;
96
+ }
97
+ function regionsCommand(parsed, context) {
98
+ const cloud = readStringFlag(parsed.flags, 'cloud') ?? 'azure';
99
+ if (cloud !== 'azure') {
100
+ context.stderr.write(`${cloud} regions are not available until the provider adapter is implemented.\n`);
101
+ return 1;
102
+ }
103
+ const query = parsed.positional[0] ?? readStringFlag(parsed.flags, 'region');
104
+ const regions = parsed.subcommand === 'search' && query ? searchRegions('azure', query) : listRegions('azure');
105
+ for (const region of regions) {
106
+ context.stdout.write(`${region.slug}\t${region.displayName}\t${region.geography}\n`);
107
+ }
108
+ return 0;
109
+ }
110
+ async function validateCommand(parsed, context) {
111
+ const project = parsed.positional[0] ?? readStringFlag(parsed.flags, 'project') ?? '.';
112
+ const projectRoot = path.resolve(context.cwd, project);
113
+ const issues = await validateGeneratedProject(projectRoot);
114
+ if (issues.length > 0) {
115
+ context.stderr.write(`${issues.join('\n')}\n`);
116
+ return 1;
117
+ }
118
+ context.stdout.write('Generated project manifest is valid.\n');
119
+ return 0;
120
+ }
121
+ function doctorCommand(parsed, context) {
122
+ const checks = [
123
+ ['node', ['--version']],
124
+ ['python3', ['--version']],
125
+ ['docker', ['--version']],
126
+ ['tofu', ['--version']]
127
+ ];
128
+ let failed = false;
129
+ for (const [command, args] of checks) {
130
+ const result = spawnSync(command, args, { encoding: 'utf8' });
131
+ if (result.status === 0) {
132
+ context.stdout.write(`[ok] ${command}: ${(result.stdout || result.stderr).split('\n')[0]}\n`);
133
+ }
134
+ else {
135
+ failed = true;
136
+ context.stdout.write(`[missing] ${command}\n`);
137
+ }
138
+ }
139
+ if (readStringFlag(parsed.flags, 'cloud') === 'azure') {
140
+ const result = spawnSync('az', ['account', 'show'], { encoding: 'utf8' });
141
+ if (result.status === 0) {
142
+ context.stdout.write('[ok] azure: authenticated\n');
143
+ }
144
+ else {
145
+ failed = true;
146
+ context.stdout.write('[missing] azure: run az login\n');
147
+ }
148
+ }
149
+ return failed ? 1 : 0;
150
+ }
151
+ function helperCommand(parsed, context, tool) {
152
+ const command = parsed.command === 'dev' ? buildDevCommand(parsed) : buildInfraCommand(parsed);
153
+ context.stdout.write(`${tool} helper command:\n${command}\n`);
154
+ return 0;
155
+ }
156
+ function buildDevCommand(parsed) {
157
+ switch (parsed.subcommand) {
158
+ case 'down':
159
+ return 'docker compose down';
160
+ case 'logs':
161
+ return 'docker compose logs -f';
162
+ case 'reset':
163
+ return 'docker compose down --volumes';
164
+ case 'up':
165
+ default: {
166
+ const profile = readStringFlag(parsed.flags, 'profile');
167
+ return profile ? `docker compose --profile ${profile} up --build` : 'docker compose up --build';
168
+ }
169
+ }
170
+ }
171
+ function buildInfraCommand(parsed) {
172
+ const env = readStringFlag(parsed.flags, 'env') ?? 'dev';
173
+ switch (parsed.subcommand) {
174
+ case 'apply':
175
+ return `tofu apply -var-file=environments/${env}.tfvars`;
176
+ case 'output':
177
+ return 'tofu output';
178
+ case 'init':
179
+ return 'tofu init';
180
+ case 'plan':
181
+ default:
182
+ return `tofu plan -var-file=environments/${env}.tfvars`;
183
+ }
184
+ }
185
+ async function optionsFromParsedArgs(parsed, cwd, includeProjectName) {
186
+ const configPath = readStringFlag(parsed.flags, 'config');
187
+ const configOptions = configPath ? await loadConfigOptions(configPath, cwd) : {};
188
+ const flagOptions = {
189
+ projectName: includeProjectName ? parsed.positional[0] ?? readStringFlag(parsed.flags, 'project') : readStringFlag(parsed.flags, 'project'),
190
+ pattern: readStringFlag(parsed.flags, 'pattern'),
191
+ cloud: readStringFlag(parsed.flags, 'cloud'),
192
+ region: readStringFlag(parsed.flags, 'region'),
193
+ includeFrontend: readBooleanFlag(parsed.flags, 'frontend'),
194
+ environments: readListFlag(parsed.flags, 'environments'),
195
+ specWorkflow: readStringFlag(parsed.flags, 'spec'),
196
+ configPath,
197
+ yes: readBooleanFlag(parsed.flags, 'yes') ?? false
198
+ };
199
+ return mergeOptions(configOptions, flagOptions);
200
+ }
201
+ function hasMissingCreateInputs(options) {
202
+ return !options.projectName || !options.pattern || !options.cloud || options.includeFrontend === undefined || !options.specWorkflow || !options.environments;
203
+ }
204
+ function printHelp(stream) {
205
+ stream.write(`Mission Control Liftoff\n\n`);
206
+ stream.write(`Commands:\n`);
207
+ stream.write(` create Generate a new project\n`);
208
+ stream.write(` plan Preview generated artifacts\n`);
209
+ stream.write(` patterns List GenAI patterns\n`);
210
+ stream.write(` providers List cloud providers\n`);
211
+ stream.write(` regions List or search provider regions\n`);
212
+ stream.write(` validate Validate a generated project manifest\n`);
213
+ stream.write(` doctor Check local readiness\n`);
214
+ stream.write(` dev Print Docker Compose helper commands\n`);
215
+ stream.write(` infra Print OpenTofu helper commands\n`);
216
+ stream.write(`\nApproved stack: ${approvedStack.join(', ')}\n`);
217
+ }
218
+ export async function createFixtureProject(options) {
219
+ const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'liftoff-'));
220
+ const plan = buildProjectPlan(options, { requireProjectName: true });
221
+ const target = artifactPath(tempRoot, [plan.safeProjectName]);
222
+ await mkdir(target, { recursive: true });
223
+ await assertNewOrEmptyDirectory(target);
224
+ await rm(target, { recursive: true, force: true });
225
+ await writeArtifacts(target, buildArtifacts(plan));
226
+ return target;
227
+ }
228
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { GeneratedArtifact } from './types.js';
2
+ export declare class FileSystemError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ export declare function resolveTargetRoot(cwd: string, projectName: string): string;
6
+ export declare function artifactPath(root: string, pathParts: string[]): string;
7
+ export declare function assertNewOrEmptyDirectory(targetRoot: string): Promise<void>;
8
+ export declare function writeArtifacts(targetRoot: string, artifacts: GeneratedArtifact[]): Promise<void>;
9
+ export declare function validateGeneratedProject(projectRoot: string): Promise<string[]>;
10
+ export declare function manifestDisplayPath(pathParts: string[]): string;
@@ -0,0 +1,65 @@
1
+ import { access, mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ export class FileSystemError extends Error {
4
+ constructor(message) {
5
+ super(message);
6
+ this.name = 'FileSystemError';
7
+ }
8
+ }
9
+ export function resolveTargetRoot(cwd, projectName) {
10
+ return path.resolve(cwd, projectName);
11
+ }
12
+ export function artifactPath(root, pathParts) {
13
+ return path.join(root, ...pathParts);
14
+ }
15
+ export async function assertNewOrEmptyDirectory(targetRoot) {
16
+ try {
17
+ const details = await stat(targetRoot);
18
+ if (!details.isDirectory()) {
19
+ throw new FileSystemError(`Target path exists and is not a directory: ${targetRoot}`);
20
+ }
21
+ const entries = await readdir(targetRoot);
22
+ if (entries.length > 0) {
23
+ throw new FileSystemError(`Target directory must be new or empty: ${targetRoot}`);
24
+ }
25
+ }
26
+ catch (error) {
27
+ if (error.code === 'ENOENT') {
28
+ return;
29
+ }
30
+ throw error;
31
+ }
32
+ }
33
+ export async function writeArtifacts(targetRoot, artifacts) {
34
+ await assertNewOrEmptyDirectory(targetRoot);
35
+ for (const artifact of artifacts) {
36
+ const targetPath = artifactPath(targetRoot, artifact.pathParts);
37
+ await mkdir(path.dirname(targetPath), { recursive: true });
38
+ await writeFile(targetPath, artifact.content, 'utf8');
39
+ }
40
+ }
41
+ export async function validateGeneratedProject(projectRoot) {
42
+ const manifestPath = path.join(projectRoot, 'liftoff.manifest.json');
43
+ const issues = [];
44
+ let manifest;
45
+ try {
46
+ manifest = JSON.parse(await readFile(manifestPath, 'utf8'));
47
+ }
48
+ catch (error) {
49
+ return [`Unable to read liftoff.manifest.json: ${error.message}`];
50
+ }
51
+ for (const artifact of manifest.artifacts) {
52
+ const targetPath = artifactPath(projectRoot, artifact.pathParts);
53
+ try {
54
+ await access(targetPath);
55
+ }
56
+ catch {
57
+ issues.push(`Missing artifact ${artifact.logicalName} at ${artifact.pathParts.join('/')}`);
58
+ }
59
+ }
60
+ return issues;
61
+ }
62
+ export function manifestDisplayPath(pathParts) {
63
+ return pathParts.join('/');
64
+ }
65
+ //# sourceMappingURL=file-system.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-system.js","sourceRoot":"","sources":["../src/file-system.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ProjectOptions, ProjectPlan } from './types.js';
2
+ export declare function promptForCreateOptions(initial: ProjectOptions): Promise<ProjectOptions>;
3
+ export declare function confirmPlan(plan: ProjectPlan, yes?: boolean): Promise<boolean>;
4
+ export declare function resolveCatalogInput(options: ProjectOptions): ProjectOptions;
@@ -0,0 +1,140 @@
1
+ import { createInterface } from 'node:readline/promises';
2
+ import { stdin as input, stdout as output } from 'node:process';
3
+ import { environments, getPattern, getProvider, getSpecWorkflow, patterns, providers, resolveRegion, specWorkflows } from './catalogs.js';
4
+ import { formatProjectPlan } from './planner.js';
5
+ export async function promptForCreateOptions(initial) {
6
+ const rl = createInterface({ input, output });
7
+ try {
8
+ const projectName = initial.projectName ?? await askRequired(rl, 'Project name');
9
+ const pattern = initial.pattern ?? await choose(rl, 'Select GenAI pattern', patterns.map((pattern) => ({
10
+ value: pattern.id,
11
+ label: `${pattern.label} (${pattern.scaffoldStatus})`,
12
+ disabled: false
13
+ })));
14
+ const cloud = initial.cloud ?? await choose(rl, 'Target cloud', providers.map((provider) => ({
15
+ value: provider.id,
16
+ label: `${provider.label}${provider.status === 'planned' ? ' - planned' : ''}`,
17
+ disabled: provider.status === 'planned'
18
+ })));
19
+ const region = initial.region ?? await promptForRegion(rl, cloud);
20
+ const includeFrontend = initial.includeFrontend ?? await confirm(rl, 'Include frontend? (Vue 3 + Tailwind)', false);
21
+ const specWorkflow = initial.specWorkflow ?? await choose(rl, 'Select spec-driven workflow', specWorkflows.map((workflow) => ({
22
+ value: workflow.id,
23
+ label: `${workflow.label}${workflow.default ? ' (default)' : ''}`,
24
+ disabled: false
25
+ })), 'openspec');
26
+ const selectedEnvironments = initial.environments ?? await askEnvironments(rl);
27
+ return {
28
+ ...initial,
29
+ projectName,
30
+ pattern,
31
+ cloud,
32
+ region,
33
+ includeFrontend,
34
+ specWorkflow,
35
+ environments: selectedEnvironments
36
+ };
37
+ }
38
+ finally {
39
+ rl.close();
40
+ }
41
+ }
42
+ export async function confirmPlan(plan, yes) {
43
+ if (yes) {
44
+ return true;
45
+ }
46
+ const rl = createInterface({ input, output });
47
+ try {
48
+ output.write(`\nGenerated plan:\n${formatProjectPlan(plan)}\n\n`);
49
+ return await confirm(rl, 'Create project?', true);
50
+ }
51
+ finally {
52
+ rl.close();
53
+ }
54
+ }
55
+ async function askRequired(rl, label) {
56
+ while (true) {
57
+ const answer = (await rl.question(`? ${label}: `)).trim();
58
+ if (answer) {
59
+ return answer;
60
+ }
61
+ }
62
+ }
63
+ async function choose(rl, label, options, defaultValue) {
64
+ while (true) {
65
+ output.write(`? ${label}:\n`);
66
+ options.forEach((option, index) => {
67
+ output.write(` ${index + 1}. ${option.label}\n`);
68
+ });
69
+ const answer = (await rl.question('Select option: ')).trim();
70
+ if (!answer && defaultValue) {
71
+ return defaultValue;
72
+ }
73
+ const selectedIndex = Number(answer) - 1;
74
+ const selected = options[selectedIndex] ?? options.find((option) => option.value === answer);
75
+ if (!selected) {
76
+ output.write('Please choose a valid option.\n');
77
+ continue;
78
+ }
79
+ if (selected.disabled) {
80
+ output.write(`${selected.label} is not available in V1.\n`);
81
+ continue;
82
+ }
83
+ return selected.value;
84
+ }
85
+ }
86
+ async function confirm(rl, label, defaultValue) {
87
+ const suffix = defaultValue ? 'Y/n' : 'y/N';
88
+ const answer = (await rl.question(`? ${label} [${suffix}]: `)).trim().toLowerCase();
89
+ if (!answer) {
90
+ return defaultValue;
91
+ }
92
+ return answer === 'y' || answer === 'yes';
93
+ }
94
+ async function promptForRegion(rl, cloud) {
95
+ const provider = getProvider(cloud);
96
+ if (!provider || provider.id !== 'azure') {
97
+ return '';
98
+ }
99
+ while (true) {
100
+ const answer = (await rl.question('? Azure region [East US / eastus]: ')).trim();
101
+ const resolution = resolveRegion(provider.id, answer);
102
+ if (resolution.status === 'resolved') {
103
+ return resolution.region.slug;
104
+ }
105
+ if (resolution.status === 'ambiguous') {
106
+ const selected = await chooseRegion(rl, resolution.matches);
107
+ return selected.slug;
108
+ }
109
+ output.write(`Unknown Azure region: ${resolution.input}. Try a region name such as eastus or korea.\n`);
110
+ }
111
+ }
112
+ async function chooseRegion(rl, matches) {
113
+ output.write('Found matching Azure regions:\n');
114
+ matches.forEach((region, index) => {
115
+ output.write(` ${index + 1}. ${region.displayName} ${region.slug}\n`);
116
+ });
117
+ while (true) {
118
+ const answer = (await rl.question('Select deployment region: ')).trim();
119
+ const selected = matches[Number(answer) - 1] ?? matches.find((region) => region.slug === answer);
120
+ if (selected) {
121
+ return selected;
122
+ }
123
+ }
124
+ }
125
+ async function askEnvironments(rl) {
126
+ const answer = (await rl.question('? Environments [dev,test,prod]: ')).trim();
127
+ if (!answer) {
128
+ return environments.map((environment) => environment.id);
129
+ }
130
+ return answer.split(',').map((value) => value.trim()).filter(Boolean);
131
+ }
132
+ export function resolveCatalogInput(options) {
133
+ return {
134
+ ...options,
135
+ pattern: options.pattern && getPattern(options.pattern)?.id,
136
+ cloud: options.cloud && getProvider(options.cloud)?.id,
137
+ specWorkflow: options.specWorkflow && getSpecWorkflow(options.specWorkflow)?.id
138
+ };
139
+ }
140
+ //# sourceMappingURL=interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../src/interactive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { ProjectOptions, ProjectPlan } from './types.js';
2
+ export declare class PlanValidationError extends Error {
3
+ readonly issues: string[];
4
+ constructor(issues: string[]);
5
+ }
6
+ interface BuildPlanOptions {
7
+ requireProjectName: boolean;
8
+ }
9
+ export declare function loadConfigOptions(configPath: string, cwd: string): Promise<ProjectOptions>;
10
+ export declare function mergeOptions(base: ProjectOptions, override: ProjectOptions): ProjectOptions;
11
+ export declare function buildProjectPlan(input: ProjectOptions, options: BuildPlanOptions): ProjectPlan;
12
+ export declare function toSafeProjectName(projectName: string): string;
13
+ export declare function formatProjectPlan(plan: ProjectPlan): string;
14
+ export {};
@@ -0,0 +1,118 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { approvedStack, environments, getEnvironment, getPattern, getProvider, getSpecWorkflow, resolveRegion, specWorkflows } from './catalogs.js';
4
+ export class PlanValidationError extends Error {
5
+ issues;
6
+ constructor(issues) {
7
+ super(issues.join('\n'));
8
+ this.issues = issues;
9
+ this.name = 'PlanValidationError';
10
+ }
11
+ }
12
+ export async function loadConfigOptions(configPath, cwd) {
13
+ const resolvedPath = path.resolve(cwd, configPath);
14
+ const raw = await readFile(resolvedPath, 'utf8');
15
+ const parsed = JSON.parse(raw);
16
+ return parsed;
17
+ }
18
+ export function mergeOptions(base, override) {
19
+ const definedOverride = Object.fromEntries(Object.entries(override).filter(([, value]) => value !== undefined));
20
+ return {
21
+ ...base,
22
+ ...definedOverride,
23
+ includeFrontend: definedOverride.includeFrontend ?? base.includeFrontend,
24
+ environments: definedOverride.environments ?? base.environments
25
+ };
26
+ }
27
+ export function buildProjectPlan(input, options) {
28
+ const issues = [];
29
+ const projectName = input.projectName?.trim();
30
+ if (options.requireProjectName && !projectName) {
31
+ issues.push('Project name is required.');
32
+ }
33
+ const pattern = input.pattern ? getPattern(input.pattern) : undefined;
34
+ if (!pattern) {
35
+ issues.push(input.pattern ? `Unknown GenAI pattern: ${input.pattern}.` : 'GenAI pattern is required.');
36
+ }
37
+ const provider = getProvider(input.cloud ?? 'azure');
38
+ if (!provider) {
39
+ issues.push(`Unknown cloud provider: ${input.cloud}.`);
40
+ }
41
+ else if (provider.status !== 'available') {
42
+ issues.push(`${provider.label} is a planned provider adapter and is not available in V1.`);
43
+ }
44
+ const specWorkflow = getSpecWorkflow(input.specWorkflow ?? specWorkflows.find((workflow) => workflow.default)?.id ?? 'openspec');
45
+ if (!specWorkflow) {
46
+ issues.push(`Unknown spec-driven workflow: ${input.specWorkflow}.`);
47
+ }
48
+ const selectedEnvironments = resolveEnvironments(input.environments);
49
+ if (selectedEnvironments.issues.length > 0) {
50
+ issues.push(...selectedEnvironments.issues);
51
+ }
52
+ const regionResolution = provider && provider.status === 'available' ? resolveRegion(provider.id, input.region) : undefined;
53
+ if (regionResolution?.status === 'ambiguous') {
54
+ issues.push(`Region "${input.region}" is ambiguous for ${provider?.label}. Use one of: ${regionResolution.matches.map((region) => region.slug).join(', ')}.`);
55
+ }
56
+ else if (regionResolution?.status === 'unknown') {
57
+ issues.push(`Unknown region "${regionResolution.input}" for ${provider?.label}.`);
58
+ }
59
+ if (issues.length > 0 || !projectName && options.requireProjectName || !pattern || !provider || !specWorkflow || provider.status !== 'available' || !regionResolution || regionResolution.status !== 'resolved') {
60
+ throw new PlanValidationError(issues);
61
+ }
62
+ const effectiveProjectName = projectName || 'liftoff-preview';
63
+ const safeProjectName = toSafeProjectName(effectiveProjectName);
64
+ return {
65
+ projectName: effectiveProjectName,
66
+ safeProjectName,
67
+ packageName: safeProjectName.replace(/_/g, '-'),
68
+ pattern,
69
+ provider,
70
+ region: regionResolution.region,
71
+ includeFrontend: input.includeFrontend ?? false,
72
+ frontendStarter: pattern.frontendStarter,
73
+ environments: selectedEnvironments.values,
74
+ specWorkflow,
75
+ approvedStack
76
+ };
77
+ }
78
+ function resolveEnvironments(values) {
79
+ if (!values || values.length === 0) {
80
+ return { values: environments, issues: [] };
81
+ }
82
+ const issues = [];
83
+ const resolved = [];
84
+ for (const value of values) {
85
+ const environment = getEnvironment(value);
86
+ if (!environment) {
87
+ issues.push(`Unknown environment: ${value}.`);
88
+ }
89
+ else if (!resolved.some((existing) => existing.id === environment.id)) {
90
+ resolved.push(environment);
91
+ }
92
+ }
93
+ return { values: resolved, issues };
94
+ }
95
+ export function toSafeProjectName(projectName) {
96
+ const safe = projectName
97
+ .trim()
98
+ .toLowerCase()
99
+ .replace(/[^a-z0-9]+/g, '-')
100
+ .replace(/^-+|-+$/g, '');
101
+ return safe || 'liftoff-project';
102
+ }
103
+ export function formatProjectPlan(plan) {
104
+ const frontendLine = plan.includeFrontend ? `Vue 3 + Tailwind (${plan.frontendStarter})` : 'Not generated';
105
+ return [
106
+ `Project: ${plan.projectName}`,
107
+ `Pattern: ${plan.pattern.label} (${plan.pattern.scaffoldStatus})`,
108
+ `Cloud: ${plan.provider.label}`,
109
+ `Region: ${plan.region.displayName} / ${plan.region.slug}`,
110
+ `Frontend: ${frontendLine}`,
111
+ `Spec workflow: ${plan.specWorkflow.label}`,
112
+ `Environments: ${plan.environments.map((environment) => environment.id).join(', ')}`,
113
+ `Approved stack: ${plan.approvedStack.join(', ')}`,
114
+ 'Local development: Docker Compose with PostgreSQL/pgvector, Redis, Azurite, Mailpit, and optional Langfuse profile',
115
+ 'Infrastructure: OpenTofu for Azure'
116
+ ].join('\n');
117
+ }
118
+ //# sourceMappingURL=planner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.js","sourceRoot":"","sources":["../src/planner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { GeneratedArtifact, LiftoffManifest, ProjectPlan } from './types.js';
2
+ export declare function buildArtifacts(plan: ProjectPlan): GeneratedArtifact[];
3
+ export declare function buildManifest(plan: ProjectPlan, artifacts: GeneratedArtifact[]): LiftoffManifest;