@salte-common/terraflow 0.1.0-alpha.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.
Files changed (131) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +278 -0
  3. package/RELEASE_SUMMARY.md +53 -0
  4. package/STANDARDS_COMPLIANCE.md +85 -0
  5. package/bin/terraflow.js +3 -0
  6. package/bin/tf.js +3 -0
  7. package/dist/commands/apply.d.ts +7 -0
  8. package/dist/commands/apply.js +12 -0
  9. package/dist/commands/base.d.ts +7 -0
  10. package/dist/commands/base.js +12 -0
  11. package/dist/commands/config.d.ts +25 -0
  12. package/dist/commands/config.js +354 -0
  13. package/dist/commands/destroy.d.ts +7 -0
  14. package/dist/commands/destroy.js +12 -0
  15. package/dist/commands/init.d.ts +68 -0
  16. package/dist/commands/init.js +131 -0
  17. package/dist/commands/plan.d.ts +7 -0
  18. package/dist/commands/plan.js +12 -0
  19. package/dist/core/backend-state.d.ts +25 -0
  20. package/dist/core/backend-state.js +77 -0
  21. package/dist/core/config.d.ts +83 -0
  22. package/dist/core/config.js +295 -0
  23. package/dist/core/context.d.ts +52 -0
  24. package/dist/core/context.js +192 -0
  25. package/dist/core/environment.d.ts +62 -0
  26. package/dist/core/environment.js +205 -0
  27. package/dist/core/errors.d.ts +22 -0
  28. package/dist/core/errors.js +36 -0
  29. package/dist/core/plugin-loader.d.ts +21 -0
  30. package/dist/core/plugin-loader.js +136 -0
  31. package/dist/core/terraform.d.ts +45 -0
  32. package/dist/core/terraform.js +247 -0
  33. package/dist/core/validator.d.ts +103 -0
  34. package/dist/core/validator.js +304 -0
  35. package/dist/index.d.ts +7 -0
  36. package/dist/index.js +184 -0
  37. package/dist/plugins/auth/aws-assume-role.d.ts +10 -0
  38. package/dist/plugins/auth/aws-assume-role.js +110 -0
  39. package/dist/plugins/auth/azure-service-principal.d.ts +10 -0
  40. package/dist/plugins/auth/azure-service-principal.js +99 -0
  41. package/dist/plugins/auth/gcp-service-account.d.ts +10 -0
  42. package/dist/plugins/auth/gcp-service-account.js +105 -0
  43. package/dist/plugins/backends/azurerm.d.ts +10 -0
  44. package/dist/plugins/backends/azurerm.js +117 -0
  45. package/dist/plugins/backends/gcs.d.ts +10 -0
  46. package/dist/plugins/backends/gcs.js +75 -0
  47. package/dist/plugins/backends/local.d.ts +11 -0
  48. package/dist/plugins/backends/local.js +37 -0
  49. package/dist/plugins/backends/s3.d.ts +10 -0
  50. package/dist/plugins/backends/s3.js +185 -0
  51. package/dist/plugins/secrets/aws-secrets.d.ts +12 -0
  52. package/dist/plugins/secrets/aws-secrets.js +125 -0
  53. package/dist/plugins/secrets/azure-keyvault.d.ts +12 -0
  54. package/dist/plugins/secrets/azure-keyvault.js +178 -0
  55. package/dist/plugins/secrets/env.d.ts +24 -0
  56. package/dist/plugins/secrets/env.js +62 -0
  57. package/dist/plugins/secrets/gcp-secret-manager.d.ts +12 -0
  58. package/dist/plugins/secrets/gcp-secret-manager.js +157 -0
  59. package/dist/templates/application/go/go.mod.template +4 -0
  60. package/dist/templates/application/go/main.template +8 -0
  61. package/dist/templates/application/go/test.template +11 -0
  62. package/dist/templates/application/javascript/main.template +14 -0
  63. package/dist/templates/application/javascript/test.template +8 -0
  64. package/dist/templates/application/python/main.template +13 -0
  65. package/dist/templates/application/python/requirements.txt.template +3 -0
  66. package/dist/templates/application/python/test.template +8 -0
  67. package/dist/templates/application/typescript/main.template +14 -0
  68. package/dist/templates/application/typescript/test.template +8 -0
  69. package/dist/templates/application/typescript/tsconfig.json.template +20 -0
  70. package/dist/templates/config/README.md.template +82 -0
  71. package/dist/templates/config/env.example.template +22 -0
  72. package/dist/templates/config/gitignore.template +40 -0
  73. package/dist/templates/config/tfwconfig.yml.template +69 -0
  74. package/dist/templates/templates/application/go/go.mod.template +4 -0
  75. package/dist/templates/templates/application/go/main.template +8 -0
  76. package/dist/templates/templates/application/go/test.template +11 -0
  77. package/dist/templates/templates/application/javascript/main.template +14 -0
  78. package/dist/templates/templates/application/javascript/test.template +8 -0
  79. package/dist/templates/templates/application/python/main.template +13 -0
  80. package/dist/templates/templates/application/python/requirements.txt.template +3 -0
  81. package/dist/templates/templates/application/python/test.template +8 -0
  82. package/dist/templates/templates/application/typescript/main.template +14 -0
  83. package/dist/templates/templates/application/typescript/test.template +8 -0
  84. package/dist/templates/templates/application/typescript/tsconfig.json.template +20 -0
  85. package/dist/templates/templates/config/README.md.template +82 -0
  86. package/dist/templates/templates/config/env.example.template +22 -0
  87. package/dist/templates/templates/config/gitignore.template +40 -0
  88. package/dist/templates/templates/config/tfwconfig.yml.template +69 -0
  89. package/dist/templates/templates/terraform/aws/_init.tf.template +24 -0
  90. package/dist/templates/templates/terraform/aws/inputs.tf.template +11 -0
  91. package/dist/templates/templates/terraform/azure/_init.tf.template +19 -0
  92. package/dist/templates/templates/terraform/azure/inputs.tf.template +11 -0
  93. package/dist/templates/templates/terraform/gcp/_init.tf.template +20 -0
  94. package/dist/templates/templates/terraform/gcp/inputs.tf.template +16 -0
  95. package/dist/templates/templates/terraform/locals.tf.template +9 -0
  96. package/dist/templates/templates/terraform/main.tf.template +8 -0
  97. package/dist/templates/templates/terraform/modules/inputs.tf.template +5 -0
  98. package/dist/templates/templates/terraform/modules/main.tf.template +2 -0
  99. package/dist/templates/templates/terraform/modules/outputs.tf.template +2 -0
  100. package/dist/templates/templates/terraform/outputs.tf.template +6 -0
  101. package/dist/templates/terraform/aws/_init.tf.template +24 -0
  102. package/dist/templates/terraform/aws/inputs.tf.template +11 -0
  103. package/dist/templates/terraform/azure/_init.tf.template +19 -0
  104. package/dist/templates/terraform/azure/inputs.tf.template +11 -0
  105. package/dist/templates/terraform/gcp/_init.tf.template +20 -0
  106. package/dist/templates/terraform/gcp/inputs.tf.template +16 -0
  107. package/dist/templates/terraform/locals.tf.template +9 -0
  108. package/dist/templates/terraform/main.tf.template +8 -0
  109. package/dist/templates/terraform/modules/inputs.tf.template +5 -0
  110. package/dist/templates/terraform/modules/main.tf.template +2 -0
  111. package/dist/templates/terraform/modules/outputs.tf.template +2 -0
  112. package/dist/templates/terraform/outputs.tf.template +6 -0
  113. package/dist/types/config.d.ts +92 -0
  114. package/dist/types/config.js +6 -0
  115. package/dist/types/context.d.ts +59 -0
  116. package/dist/types/context.js +6 -0
  117. package/dist/types/index.d.ts +7 -0
  118. package/dist/types/index.js +23 -0
  119. package/dist/types/plugins.d.ts +77 -0
  120. package/dist/types/plugins.js +6 -0
  121. package/dist/utils/cloud.d.ts +43 -0
  122. package/dist/utils/cloud.js +150 -0
  123. package/dist/utils/git.d.ts +88 -0
  124. package/dist/utils/git.js +258 -0
  125. package/dist/utils/logger.d.ts +67 -0
  126. package/dist/utils/logger.js +121 -0
  127. package/dist/utils/scaffolding.d.ts +92 -0
  128. package/dist/utils/scaffolding.js +338 -0
  129. package/dist/utils/templates.d.ts +25 -0
  130. package/dist/utils/templates.js +70 -0
  131. package/package.json +60 -0
@@ -0,0 +1,354 @@
1
+ "use strict";
2
+ /**
3
+ * Config command handler
4
+ * Manages Terraflow configuration
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.ConfigCommand = void 0;
11
+ const fs_1 = require("fs");
12
+ const path_1 = require("path");
13
+ const js_yaml_1 = __importDefault(require("js-yaml"));
14
+ const config_1 = require("../core/config");
15
+ const logger_1 = require("../utils/logger");
16
+ /**
17
+ * Fields that should always be masked
18
+ * These are exact field names that contain sensitive data
19
+ */
20
+ const ALWAYS_MASKED_FIELDS = [
21
+ 'client_secret',
22
+ 'secret_access_key',
23
+ 'session_token',
24
+ 'access_key_id',
25
+ 'access_key',
26
+ 'api_key',
27
+ 'password',
28
+ 'secret',
29
+ 'key', // Only mask if it's clearly a credential key, not a generic key field
30
+ 'token',
31
+ ];
32
+ /**
33
+ * Sensitive field patterns that should be masked
34
+ */
35
+ const SENSITIVE_PATTERNS = [
36
+ /password$/i,
37
+ /secret$/i,
38
+ /.*_secret$/i,
39
+ /.*_key$/i, // But not role_arn, kms_key_id, etc.
40
+ /token$/i,
41
+ /credential$/i,
42
+ /access.*key$/i,
43
+ /session.*token$/i,
44
+ /client.*secret$/i,
45
+ ];
46
+ /**
47
+ * Fields that should NOT be masked (even if they match patterns)
48
+ */
49
+ const EXCLUDED_FIELDS = ['role_arn', 'kms_key_id', 'key', 'key_file', 'key_id'];
50
+ /**
51
+ * Check if a field name indicates sensitive data
52
+ */
53
+ function isSensitiveField(fieldName) {
54
+ // Check if field is explicitly excluded
55
+ if (EXCLUDED_FIELDS.includes(fieldName)) {
56
+ return false;
57
+ }
58
+ const lowerName = fieldName.toLowerCase();
59
+ // Check exact matches first (these are always sensitive)
60
+ if (ALWAYS_MASKED_FIELDS.includes(lowerName)) {
61
+ return true;
62
+ }
63
+ // For 'key', only mask if it's clearly a credential (not key_file, key_id, etc.)
64
+ if (lowerName === 'key') {
65
+ // Don't mask generic 'key' fields - too many false positives
66
+ return false;
67
+ }
68
+ // Check patterns (e.g., client_secret, access_key, session_token)
69
+ return SENSITIVE_PATTERNS.some((pattern) => pattern.test(fieldName));
70
+ }
71
+ /**
72
+ * Mask sensitive values in an object recursively
73
+ */
74
+ function maskSensitiveValues(obj, path = '') {
75
+ if (obj === null || obj === undefined) {
76
+ return obj;
77
+ }
78
+ if (Array.isArray(obj)) {
79
+ return obj.map((item, index) => maskSensitiveValues(item, `${path}[${index}]`));
80
+ }
81
+ if (typeof obj === 'object') {
82
+ const masked = {};
83
+ for (const key in obj) {
84
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
85
+ const fullPath = path ? `${path}.${key}` : key;
86
+ const value = obj[key];
87
+ if (isSensitiveField(key) || isSensitiveField(fullPath)) {
88
+ // Mask the value
89
+ if (typeof value === 'string' && value.length > 0) {
90
+ masked[key] = '***MASKED***';
91
+ }
92
+ else {
93
+ masked[key] = value;
94
+ }
95
+ }
96
+ else {
97
+ // Recursively mask nested objects
98
+ masked[key] = maskSensitiveValues(value, fullPath);
99
+ }
100
+ }
101
+ }
102
+ return masked;
103
+ }
104
+ return obj;
105
+ }
106
+ /**
107
+ * Config command handler class
108
+ */
109
+ class ConfigCommand {
110
+ /**
111
+ * Show resolved configuration
112
+ * Displays merged configuration with source tracking and masked sensitive values
113
+ */
114
+ static async show(cliOptions = {}) {
115
+ try {
116
+ // Load configuration
117
+ const config = await config_1.ConfigManager.load(cliOptions);
118
+ // Mask sensitive values
119
+ const maskedConfig = maskSensitiveValues(config);
120
+ // Format as YAML
121
+ const yamlOutput = js_yaml_1.default.dump(maskedConfig, {
122
+ indent: 2,
123
+ lineWidth: 120,
124
+ quotingType: '"',
125
+ forceQuotes: false,
126
+ });
127
+ logger_1.Logger.info('Resolved configuration:');
128
+ logger_1.Logger.info('');
129
+ logger_1.Logger.info(yamlOutput);
130
+ // Show configuration sources
131
+ logger_1.Logger.info('');
132
+ logger_1.Logger.info('Configuration sources:');
133
+ logger_1.Logger.info(' CLI: Command-line arguments (highest priority)');
134
+ logger_1.Logger.info(' ENV: Environment variables');
135
+ logger_1.Logger.info(' FILE: Configuration file (.tfwconfig.yml)');
136
+ logger_1.Logger.info(' DEFAULT: Hard-coded defaults (lowest priority)');
137
+ logger_1.Logger.info('');
138
+ logger_1.Logger.info('Note: Sensitive values are masked with ***MASKED***');
139
+ }
140
+ catch (error) {
141
+ logger_1.Logger.error(`Failed to show configuration: ${error instanceof Error ? error.message : String(error)}`);
142
+ throw error;
143
+ }
144
+ }
145
+ /**
146
+ * Generate skeleton configuration file
147
+ * Creates a .tfwconfig.yml with commented examples
148
+ */
149
+ static async init(outputPath, workingDir = process.cwd()) {
150
+ try {
151
+ const configPath = outputPath || (0, path_1.join)(workingDir, '.tfwconfig.yml');
152
+ // Check if file already exists
153
+ if ((0, fs_1.existsSync)(configPath)) {
154
+ logger_1.Logger.warn(`Configuration file already exists at ${configPath}`);
155
+ logger_1.Logger.warn('Use --output flag to specify a different filename');
156
+ throw new Error('Configuration file already exists');
157
+ }
158
+ // Generate skeleton
159
+ const skeleton = ConfigCommand.generateConfigSkeleton();
160
+ // Ensure directory exists
161
+ const dir = (0, path_1.dirname)(configPath);
162
+ if (!(0, fs_1.existsSync)(dir)) {
163
+ (0, fs_1.mkdirSync)(dir, { recursive: true });
164
+ }
165
+ // Write file
166
+ (0, fs_1.writeFileSync)(configPath, skeleton, 'utf8');
167
+ logger_1.Logger.success(`✅ Configuration skeleton created at ${configPath}`);
168
+ }
169
+ catch (error) {
170
+ logger_1.Logger.error(`Failed to create config file: ${error instanceof Error ? error.message : String(error)}`);
171
+ throw error;
172
+ }
173
+ }
174
+ /**
175
+ * Generate skeleton configuration file content
176
+ */
177
+ static generateConfigSkeleton() {
178
+ return `# Terraflow Configuration File
179
+ # This file defines your Terraflow configuration
180
+ # See https://github.com/salte-common/terraflow/blob/main/docs/configuration.md for full documentation
181
+
182
+ # Global Settings
183
+ # ===============
184
+
185
+ # Workspace name (optional - will be derived if not specified)
186
+ # Priority: CLI > ENV > Tag > Branch > Hostname
187
+ workspace: development
188
+
189
+ # Terraform working directory (default: ./terraform)
190
+ # This is where your Terraform files (.tf) should be located
191
+ working-dir: ./terraform
192
+
193
+ # Skip git commit check for destructive operations
194
+ # Set to true to skip validation that requires a clean git working directory
195
+ skip-commit-check: false
196
+
197
+ # Backend Configuration
198
+ # ====================
199
+ # Terraform backend for state storage
200
+ # Options: local | s3 | azurerm | gcs
201
+
202
+ backend:
203
+ # Backend type
204
+ type: local
205
+
206
+ # Backend-specific configuration
207
+ config:
208
+ # Local backend (no additional config needed)
209
+ # State is stored in terraform.tfstate in the working directory
210
+
211
+ # S3 Backend Example:
212
+ # type: s3
213
+ # config:
214
+ # bucket: my-terraform-state-bucket
215
+ # key: terraform.tfstate
216
+ # region: us-east-1
217
+ # encrypt: true # Always recommended
218
+ # dynamodb_table: terraform-statelock # For state locking
219
+ # kms_key_id: arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012 # Optional: KMS encryption
220
+
221
+ # Azure RM Backend Example:
222
+ # type: azurerm
223
+ # config:
224
+ # resource_group_name: terraform-state-rg
225
+ # storage_account_name: terraformstate
226
+ # container_name: terraform-state
227
+ # key: terraform.tfstate
228
+
229
+ # GCS Backend Example:
230
+ # type: gcs
231
+ # config:
232
+ # bucket: terraform-state-bucket
233
+ # prefix: terraform/state
234
+ # credentials: /path/to/service-account-key.json # Optional: path to service account key
235
+
236
+ # Secrets Management
237
+ # ==================
238
+ # Secrets provider for retrieving Terraform variables
239
+ # Options: env | aws-secrets | azure-keyvault | gcp-secret-manager
240
+
241
+ # secrets:
242
+ # # Secrets provider type
243
+ # provider: env
244
+ #
245
+ # # Provider-specific configuration
246
+ # config:
247
+ # # Environment secrets (no additional config needed)
248
+ # # Secrets are loaded from .env file or existing environment variables
249
+ # # Use TF_VAR_* prefix in .env file for Terraform variables
250
+ #
251
+ # # AWS Secrets Manager Example:
252
+ # # provider: aws-secrets
253
+ # # config:
254
+ # # secret_name: myapp/terraform-vars
255
+ # # region: us-east-1 # Optional: uses AWS_REGION if not specified
256
+ #
257
+ # # Azure Key Vault Example:
258
+ # # provider: azure-keyvault
259
+ # # config:
260
+ # # vault_name: my-keyvault
261
+ # # secret_name: terraform-vars
262
+ #
263
+ # # GCP Secret Manager Example:
264
+ # # provider: gcp-secret-manager
265
+ # # config:
266
+ # # project_id: my-gcp-project
267
+ # # secret_id: terraform-vars
268
+
269
+ # Authentication
270
+ # ==============
271
+ # Cloud provider authentication configuration
272
+ # Used to assume roles or authenticate with cloud providers
273
+
274
+ # auth:
275
+ # # AWS Assume Role Example:
276
+ # # assume_role:
277
+ # # role_arn: arn:aws:iam::123456789012:role/terraform-role
278
+ # # session_name: terraflow-session # Optional: default is "terraflow-session"
279
+ # # duration: 3600 # Optional: session duration in seconds (default: 3600)
280
+ #
281
+ # # Azure Service Principal Example:
282
+ # # service_principal:
283
+ # # client_id: your-client-id
284
+ # # tenant_id: your-tenant-id
285
+ # # client_secret: your-client-secret # Optional: can use Azure CLI or managed identity
286
+ #
287
+ # # GCP Service Account Example:
288
+ # # service_account:
289
+ # # key_file: /path/to/service-account-key.json
290
+
291
+ # Terraform Variables
292
+ # ===================
293
+ # Variables passed to Terraform as TF_VAR_* environment variables
294
+ # These are converted automatically - no TF_VAR_ prefix needed in config
295
+
296
+ # variables:
297
+ # environment: development
298
+ # region: us-east-1
299
+ # instance_count: 3
300
+
301
+ # Workspace Derivation Strategy
302
+ # =============================
303
+ # Order of precedence for workspace name resolution
304
+ # Default: [cli, env, tag, branch, hostname]
305
+
306
+ # workspace_strategy:
307
+ # - cli # Command-line --workspace flag
308
+ # - env # TERRAFLOW_WORKSPACE environment variable
309
+ # - tag # Git tag (if on a tag)
310
+ # - branch # Git branch (if not ephemeral)
311
+ # - hostname # System hostname (fallback)
312
+
313
+ # Validation Configuration
314
+ # ========================
315
+ # Validation rules for Terraform operations
316
+
317
+ # validations:
318
+ # # Require git commit before apply/destroy
319
+ # require_git_commit: true
320
+ #
321
+ # # List of allowed workspace names (empty = allow all)
322
+ # allowed_workspaces:
323
+ # - development
324
+ # - staging
325
+ # - production
326
+
327
+ # Logging Configuration
328
+ # =====================
329
+ # Control logging behavior
330
+
331
+ # logging:
332
+ # # Log level: error | warn | info | debug
333
+ # level: info
334
+ #
335
+ # # Enable Terraform log output
336
+ # terraform_log: false
337
+ #
338
+ # # Terraform log level: TRACE | DEBUG | INFO | WARN | ERROR
339
+ # terraform_log_level: TRACE
340
+
341
+ # Template Variables
342
+ # ==================
343
+ # Configuration values support template variables using \${VAR} syntax
344
+ # Available variables:
345
+ # - Environment variables (e.g., \${AWS_REGION})
346
+ # - Cloud provider info (e.g., \${AWS_ACCOUNT_ID}, \${AZURE_SUBSCRIPTION_ID}, \${GCP_PROJECT_ID})
347
+ # - VCS info (e.g., \${GITHUB_REPOSITORY}, \${GIT_BRANCH}, \${GIT_COMMIT_SHA})
348
+ # Example:
349
+ # bucket: \${AWS_REGION}-\${AWS_ACCOUNT_ID}-terraform-state
350
+ `;
351
+ }
352
+ }
353
+ exports.ConfigCommand = ConfigCommand;
354
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Destroy command handler
3
+ * Executes terraform destroy with Terraflow enhancements
4
+ */
5
+ export declare class DestroyCommand {
6
+ }
7
+ //# sourceMappingURL=destroy.d.ts.map
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ /**
3
+ * Destroy command handler
4
+ * Executes terraform destroy with Terraflow enhancements
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.DestroyCommand = void 0;
8
+ // TODO: Implement destroy command
9
+ class DestroyCommand {
10
+ }
11
+ exports.DestroyCommand = DestroyCommand;
12
+ //# sourceMappingURL=destroy.js.map
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Init command handler
3
+ * Scaffolds a new infrastructure project with opinionated defaults
4
+ */
5
+ /**
6
+ * Init command options
7
+ */
8
+ export interface InitOptions {
9
+ provider?: string;
10
+ language?: string;
11
+ workingDir?: string;
12
+ force?: boolean;
13
+ }
14
+ /**
15
+ * Init command handler for project scaffolding
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * // Create AWS project with JavaScript
20
+ * await InitCommand.execute('my-project', {
21
+ * provider: 'aws',
22
+ * language: 'javascript'
23
+ * });
24
+ *
25
+ * // Create Azure project with TypeScript
26
+ * await InitCommand.execute('my-project', {
27
+ * provider: 'azure',
28
+ * language: 'typescript'
29
+ * });
30
+ * ```
31
+ */
32
+ export declare class InitCommand {
33
+ /**
34
+ * Execute the init command to scaffold a new infrastructure project
35
+ *
36
+ * Creates a complete project structure with:
37
+ * - Terraform configuration files for the specified cloud provider
38
+ * - Application code templates in the specified language
39
+ * - Pre-configured `.tfwconfig.yml` with backend settings
40
+ * - Example `.env.example` file
41
+ * - Complete `.gitignore` and `README.md`
42
+ *
43
+ * @param projectName - Name of the project to create (optional, defaults to current directory)
44
+ * @param options - Init command options
45
+ * @param options.provider - Cloud provider: 'aws', 'azure', or 'gcp' (default: 'aws')
46
+ * @param options.language - Application language: 'javascript', 'typescript', 'python', or 'go' (default: 'javascript')
47
+ * @param options.workingDir - Directory where to create the project (default: current directory)
48
+ * @param options.force - Overwrite existing files if present (default: false)
49
+ * @throws {ConfigError} If validation fails (invalid project name, provider, language, or non-empty directory)
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * // Create project in current directory
54
+ * await InitCommand.execute(undefined, { provider: 'aws' });
55
+ *
56
+ * // Create named project
57
+ * await InitCommand.execute('my-infrastructure', {
58
+ * provider: 'gcp',
59
+ * language: 'python'
60
+ * });
61
+ *
62
+ * // Force overwrite existing files
63
+ * await InitCommand.execute('my-project', { force: true });
64
+ * ```
65
+ */
66
+ static execute(projectName: string | undefined, options?: InitOptions): Promise<void>;
67
+ }
68
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ /**
3
+ * Init command handler
4
+ * Scaffolds a new infrastructure project with opinionated defaults
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.InitCommand = void 0;
8
+ const path_1 = require("path");
9
+ const logger_1 = require("../utils/logger");
10
+ const errors_1 = require("../core/errors");
11
+ const scaffolding_1 = require("../utils/scaffolding");
12
+ /**
13
+ * Init command handler for project scaffolding
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * // Create AWS project with JavaScript
18
+ * await InitCommand.execute('my-project', {
19
+ * provider: 'aws',
20
+ * language: 'javascript'
21
+ * });
22
+ *
23
+ * // Create Azure project with TypeScript
24
+ * await InitCommand.execute('my-project', {
25
+ * provider: 'azure',
26
+ * language: 'typescript'
27
+ * });
28
+ * ```
29
+ */
30
+ class InitCommand {
31
+ /**
32
+ * Execute the init command to scaffold a new infrastructure project
33
+ *
34
+ * Creates a complete project structure with:
35
+ * - Terraform configuration files for the specified cloud provider
36
+ * - Application code templates in the specified language
37
+ * - Pre-configured `.tfwconfig.yml` with backend settings
38
+ * - Example `.env.example` file
39
+ * - Complete `.gitignore` and `README.md`
40
+ *
41
+ * @param projectName - Name of the project to create (optional, defaults to current directory)
42
+ * @param options - Init command options
43
+ * @param options.provider - Cloud provider: 'aws', 'azure', or 'gcp' (default: 'aws')
44
+ * @param options.language - Application language: 'javascript', 'typescript', 'python', or 'go' (default: 'javascript')
45
+ * @param options.workingDir - Directory where to create the project (default: current directory)
46
+ * @param options.force - Overwrite existing files if present (default: false)
47
+ * @throws {ConfigError} If validation fails (invalid project name, provider, language, or non-empty directory)
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * // Create project in current directory
52
+ * await InitCommand.execute(undefined, { provider: 'aws' });
53
+ *
54
+ * // Create named project
55
+ * await InitCommand.execute('my-infrastructure', {
56
+ * provider: 'gcp',
57
+ * language: 'python'
58
+ * });
59
+ *
60
+ * // Force overwrite existing files
61
+ * await InitCommand.execute('my-project', { force: true });
62
+ * ```
63
+ */
64
+ static async execute(projectName, options = {}) {
65
+ const provider = options.provider || 'aws';
66
+ const language = options.language || 'javascript';
67
+ const workingDir = options.workingDir || process.cwd();
68
+ const force = options.force || false;
69
+ // Validate provider
70
+ if (!(0, scaffolding_1.validateProvider)(provider)) {
71
+ throw new errors_1.ConfigError(`Invalid provider "${provider}". Must be one of: aws, azure, gcp.\n` +
72
+ `Example: terraflow init my-project --provider aws`);
73
+ }
74
+ // Validate language
75
+ if (!(0, scaffolding_1.validateLanguage)(language)) {
76
+ throw new errors_1.ConfigError(`Invalid language "${language}". Must be one of: javascript, typescript, python, go.\n` +
77
+ `Example: terraflow init my-project --language typescript`);
78
+ }
79
+ // Determine project directory
80
+ const projectDir = projectName ? (0, path_1.resolve)(workingDir, projectName) : (0, path_1.resolve)(workingDir);
81
+ // Validate project name if provided
82
+ if (projectName && !(0, scaffolding_1.validateProjectName)(projectName)) {
83
+ throw new errors_1.ConfigError(`Invalid project name "${projectName}". Project name must contain only alphanumeric characters, hyphens, and underscores.\n` +
84
+ `Valid examples: "my-project", "my_project", "project123"\n` +
85
+ `Invalid examples: "my project" (spaces), "my.project" (dots), "my/project" (slashes)`);
86
+ }
87
+ // Check if directory exists and is not empty
88
+ const isEmpty = await (0, scaffolding_1.isDirectoryEmpty)(projectDir);
89
+ if (!isEmpty && !force) {
90
+ throw new errors_1.ConfigError(`Directory "${projectDir}" is not empty. Use --force to overwrite existing files.\n` +
91
+ `Warning: Using --force will overwrite existing files in the target directory.\n` +
92
+ `Example: terraflow init ${projectName || 'my-project'} --force`);
93
+ }
94
+ logger_1.Logger.info(`🚀 Initializing project "${projectName || 'current directory'}"...`);
95
+ logger_1.Logger.info(` Provider: ${provider}`);
96
+ logger_1.Logger.info(` Language: ${language}`);
97
+ // Create project structure
98
+ await (0, scaffolding_1.createProjectStructure)(projectDir);
99
+ // Generate files
100
+ const finalProjectName = projectName || 'project';
101
+ await (0, scaffolding_1.generateTerraformFiles)(projectDir, provider, finalProjectName);
102
+ await (0, scaffolding_1.generateApplicationFiles)(projectDir, language, finalProjectName);
103
+ await (0, scaffolding_1.generateConfigFiles)(projectDir, provider, language, finalProjectName);
104
+ logger_1.Logger.info(`✅ Project "${projectName || 'current directory'}" initialized successfully!`);
105
+ logger_1.Logger.info('');
106
+ logger_1.Logger.info('Next steps:');
107
+ if (projectName) {
108
+ logger_1.Logger.info(` 1. cd ${projectName}`);
109
+ logger_1.Logger.info(' 2. cp .env.example .env');
110
+ }
111
+ else {
112
+ logger_1.Logger.info(' 1. cp .env.example .env');
113
+ logger_1.Logger.info(' 2. Edit .env with your credentials');
114
+ }
115
+ if (projectName) {
116
+ logger_1.Logger.info(' 3. Edit .env with your credentials');
117
+ logger_1.Logger.info(' 4. Review and update .tfwconfig.yml');
118
+ logger_1.Logger.info(' 5. terraflow init');
119
+ logger_1.Logger.info(' 6. terraflow plan');
120
+ }
121
+ else {
122
+ logger_1.Logger.info(' 3. Review and update .tfwconfig.yml');
123
+ logger_1.Logger.info(' 4. terraflow init');
124
+ logger_1.Logger.info(' 5. terraflow plan');
125
+ }
126
+ logger_1.Logger.info('');
127
+ logger_1.Logger.info('Documentation: ./README.md');
128
+ }
129
+ }
130
+ exports.InitCommand = InitCommand;
131
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Plan command handler
3
+ * Executes terraform plan with Terraflow enhancements
4
+ */
5
+ export declare class PlanCommand {
6
+ }
7
+ //# sourceMappingURL=plan.d.ts.map
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ /**
3
+ * Plan command handler
4
+ * Executes terraform plan with Terraflow enhancements
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.PlanCommand = void 0;
8
+ // TODO: Implement plan command
9
+ class PlanCommand {
10
+ }
11
+ exports.PlanCommand = PlanCommand;
12
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Backend state management
3
+ * Stores previous backend configuration to detect migrations
4
+ */
5
+ import type { BackendConfig } from '../types/config';
6
+ /**
7
+ * Load previous backend state
8
+ * @param workingDir - Working directory
9
+ * @returns Previous backend configuration or null
10
+ */
11
+ export declare function loadBackendState(workingDir: string): BackendConfig | null;
12
+ /**
13
+ * Save backend state
14
+ * @param workingDir - Working directory
15
+ * @param backend - Backend configuration to save
16
+ */
17
+ export declare function saveBackendState(workingDir: string, backend: BackendConfig): void;
18
+ /**
19
+ * Detect if backend has changed
20
+ * @param workingDir - Working directory
21
+ * @param currentBackend - Current backend configuration
22
+ * @returns Previous backend type if changed, null otherwise
23
+ */
24
+ export declare function detectBackendMigration(workingDir: string, currentBackend: BackendConfig): string | null;
25
+ //# sourceMappingURL=backend-state.d.ts.map