genbox 1.0.11 → 1.0.13

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,288 @@
1
+ "use strict";
2
+ /**
3
+ * Strict Mode Enforcement
4
+ *
5
+ * In strict mode (default for v4):
6
+ * - All app types must be explicit (no inference from names)
7
+ * - All ports must be explicit or use $detect markers
8
+ * - All connections must be declared in connects_to
9
+ * - No implicit defaults are applied
10
+ *
11
+ * This ensures reproducible, predictable behavior across
12
+ * different environments and team members.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.DEFAULT_STRICT_CONFIG = void 0;
16
+ exports.validateStrictMode = validateStrictMode;
17
+ exports.getStrictModeSettings = getStrictModeSettings;
18
+ exports.isStrictModeEnabled = isStrictModeEnabled;
19
+ exports.formatStrictViolations = formatStrictViolations;
20
+ exports.generateStrictFixes = generateStrictFixes;
21
+ const schema_v3_1 = require("./schema-v3");
22
+ // ============================================
23
+ // Default Strict Mode Settings
24
+ // ============================================
25
+ exports.DEFAULT_STRICT_CONFIG = {
26
+ enabled: true,
27
+ allow_detect: true,
28
+ warnings_as_errors: false,
29
+ };
30
+ // ============================================
31
+ // Strict Mode Validation
32
+ // ============================================
33
+ /**
34
+ * Validate a configuration against strict mode rules
35
+ */
36
+ function validateStrictMode(config, strictConfig = {}) {
37
+ const settings = { ...exports.DEFAULT_STRICT_CONFIG, ...strictConfig };
38
+ const violations = [];
39
+ let explicitValues = 0;
40
+ let detectMarkers = 0;
41
+ let inferredValues = 0;
42
+ // Check each app
43
+ for (const [appName, appConfig] of Object.entries(config.apps || {})) {
44
+ const appPath = `apps.${appName}`;
45
+ // Check app type
46
+ if (!appConfig.type) {
47
+ violations.push({
48
+ path: `${appPath}.type`,
49
+ type: 'missing_type',
50
+ message: `App "${appName}" has no type specified`,
51
+ suggestion: `Add explicit "type: frontend | backend | worker | gateway"`,
52
+ severity: settings.enabled ? 'error' : 'warning',
53
+ });
54
+ inferredValues++;
55
+ }
56
+ else if ((0, schema_v3_1.isDetectMarker)(appConfig.type)) {
57
+ if (!settings.allow_detect) {
58
+ violations.push({
59
+ path: `${appPath}.type`,
60
+ type: 'implicit_value',
61
+ message: `$detect markers are not allowed in strict mode`,
62
+ suggestion: `Replace $detect with explicit type value`,
63
+ severity: 'error',
64
+ });
65
+ }
66
+ detectMarkers++;
67
+ }
68
+ else {
69
+ explicitValues++;
70
+ // Check for naming-based inference (when type matches name pattern)
71
+ if (isTypeInferredFromName(appName, appConfig.type)) {
72
+ violations.push({
73
+ path: `${appPath}.type`,
74
+ type: 'naming_inference',
75
+ message: `App type "${appConfig.type}" appears to match naming convention`,
76
+ suggestion: `This is fine, but ensure the type is intentional, not just matching the name`,
77
+ severity: 'warning',
78
+ });
79
+ }
80
+ }
81
+ // Check port for backend apps
82
+ if (appConfig.type === 'backend' || appConfig.type === 'gateway') {
83
+ if (!appConfig.port) {
84
+ violations.push({
85
+ path: `${appPath}.port`,
86
+ type: 'missing_port',
87
+ message: `Backend app "${appName}" has no port specified`,
88
+ suggestion: `Add explicit "port: <number>" or "port: $detect"`,
89
+ severity: settings.enabled ? 'error' : 'warning',
90
+ });
91
+ inferredValues++;
92
+ }
93
+ else if ((0, schema_v3_1.isDetectMarker)(appConfig.port)) {
94
+ if (!settings.allow_detect) {
95
+ violations.push({
96
+ path: `${appPath}.port`,
97
+ type: 'implicit_value',
98
+ message: `$detect markers are not allowed in strict mode`,
99
+ suggestion: `Replace $detect with explicit port number`,
100
+ severity: 'error',
101
+ });
102
+ }
103
+ detectMarkers++;
104
+ }
105
+ else {
106
+ explicitValues++;
107
+ }
108
+ }
109
+ // Check connections (v4 style)
110
+ const v4App = appConfig;
111
+ if (v4App.connects_to) {
112
+ for (const [connName, connConfig] of Object.entries(v4App.connects_to)) {
113
+ if (!connConfig || typeof connConfig !== 'object') {
114
+ violations.push({
115
+ path: `${appPath}.connects_to.${connName}`,
116
+ type: 'undeclared_connection',
117
+ message: `Invalid connection configuration for "${connName}"`,
118
+ suggestion: `Specify connection mode: { mode: local | staging | production }`,
119
+ severity: 'error',
120
+ });
121
+ }
122
+ explicitValues++;
123
+ }
124
+ }
125
+ // Check for legacy requires (v3 style)
126
+ const v3App = appConfig;
127
+ if (v3App.requires) {
128
+ for (const [depName, requirement] of Object.entries(v3App.requires)) {
129
+ violations.push({
130
+ path: `${appPath}.requires.${depName}`,
131
+ type: 'undeclared_connection',
132
+ message: `Legacy "requires" syntax used`,
133
+ suggestion: `Use "connects_to: { ${depName}: { mode: local } }" instead`,
134
+ severity: settings.enabled ? 'error' : 'warning',
135
+ });
136
+ }
137
+ }
138
+ }
139
+ // Check provides/infrastructure
140
+ const v4Config = config;
141
+ if (v4Config.provides) {
142
+ for (const [infraName, infraConfig] of Object.entries(v4Config.provides)) {
143
+ if (!infraConfig.type || !infraConfig.image || !infraConfig.port) {
144
+ violations.push({
145
+ path: `provides.${infraName}`,
146
+ type: 'implicit_value',
147
+ message: `Infrastructure "${infraName}" missing required fields`,
148
+ suggestion: `Specify type, image, and port explicitly`,
149
+ severity: 'error',
150
+ });
151
+ }
152
+ else {
153
+ explicitValues += 3; // type, image, port
154
+ }
155
+ }
156
+ }
157
+ // Calculate summary
158
+ const errors = violations.filter(v => v.severity === 'error').length;
159
+ const warnings = violations.filter(v => v.severity === 'warning').length;
160
+ // In strict mode with warnings_as_errors, warnings become errors
161
+ const finalErrors = settings.warnings_as_errors ? errors + warnings : errors;
162
+ return {
163
+ valid: finalErrors === 0,
164
+ violations,
165
+ summary: {
166
+ errors,
167
+ warnings,
168
+ explicit_values: explicitValues,
169
+ detect_markers: detectMarkers,
170
+ inferred_values: inferredValues,
171
+ },
172
+ };
173
+ }
174
+ /**
175
+ * Check if a type appears to be inferred from the app name
176
+ */
177
+ function isTypeInferredFromName(appName, type) {
178
+ const nameLower = appName.toLowerCase();
179
+ if (type === 'frontend') {
180
+ return /web|frontend|ui|client|app/.test(nameLower);
181
+ }
182
+ if (type === 'backend') {
183
+ return /api|backend|server|service/.test(nameLower);
184
+ }
185
+ if (type === 'worker') {
186
+ return /worker|queue|job|processor/.test(nameLower);
187
+ }
188
+ if (type === 'gateway') {
189
+ return /gateway|proxy|router/.test(nameLower);
190
+ }
191
+ return false;
192
+ }
193
+ // ============================================
194
+ // Strict Mode Helpers
195
+ // ============================================
196
+ /**
197
+ * Get strict mode settings from config
198
+ */
199
+ function getStrictModeSettings(config) {
200
+ const v4Config = config;
201
+ if (v4Config.version === 4 && v4Config.strict) {
202
+ return { ...exports.DEFAULT_STRICT_CONFIG, ...v4Config.strict };
203
+ }
204
+ // v3 configs default to lenient mode
205
+ if (config.version !== 4) {
206
+ return {
207
+ enabled: false,
208
+ allow_detect: true,
209
+ warnings_as_errors: false,
210
+ };
211
+ }
212
+ return exports.DEFAULT_STRICT_CONFIG;
213
+ }
214
+ /**
215
+ * Check if strict mode is enabled
216
+ */
217
+ function isStrictModeEnabled(config) {
218
+ return getStrictModeSettings(config).enabled;
219
+ }
220
+ /**
221
+ * Format strict mode violations for display
222
+ */
223
+ function formatStrictViolations(result) {
224
+ const lines = [];
225
+ if (result.valid) {
226
+ lines.push('✓ Strict mode validation passed');
227
+ }
228
+ else {
229
+ lines.push('✗ Strict mode validation failed');
230
+ }
231
+ lines.push('');
232
+ lines.push(`Summary:`);
233
+ lines.push(` Explicit values: ${result.summary.explicit_values}`);
234
+ lines.push(` $detect markers: ${result.summary.detect_markers}`);
235
+ lines.push(` Inferred values: ${result.summary.inferred_values}`);
236
+ lines.push(` Errors: ${result.summary.errors}`);
237
+ lines.push(` Warnings: ${result.summary.warnings}`);
238
+ if (result.violations.length > 0) {
239
+ lines.push('');
240
+ lines.push('Violations:');
241
+ for (const violation of result.violations) {
242
+ const icon = violation.severity === 'error' ? '✗' : '⚠';
243
+ lines.push(` ${icon} ${violation.path}`);
244
+ lines.push(` ${violation.message}`);
245
+ lines.push(` → ${violation.suggestion}`);
246
+ }
247
+ }
248
+ return lines.join('\n');
249
+ }
250
+ /**
251
+ * Generate fixes for strict mode violations
252
+ */
253
+ function generateStrictFixes(config, result) {
254
+ const fixes = [];
255
+ for (const violation of result.violations) {
256
+ if (violation.type === 'missing_type') {
257
+ // Add $detect marker for missing types
258
+ fixes.push({
259
+ path: violation.path,
260
+ action: 'add',
261
+ value: '$detect',
262
+ description: `Add $detect marker to auto-detect type`,
263
+ });
264
+ }
265
+ if (violation.type === 'missing_port') {
266
+ fixes.push({
267
+ path: violation.path,
268
+ action: 'add',
269
+ value: '$detect',
270
+ description: `Add $detect marker to auto-detect port`,
271
+ });
272
+ }
273
+ if (violation.type === 'undeclared_connection' && violation.path.includes('requires')) {
274
+ // Convert requires to connects_to
275
+ const match = violation.path.match(/apps\.(\w+)\.requires\.(\w+)/);
276
+ if (match) {
277
+ const [, appName, depName] = match;
278
+ fixes.push({
279
+ path: `apps.${appName}.connects_to.${depName}`,
280
+ action: 'add',
281
+ value: { mode: 'local', required: true },
282
+ description: `Convert requires.${depName} to connects_to`,
283
+ });
284
+ }
285
+ }
286
+ }
287
+ return fixes;
288
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genbox",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "Genbox CLI - AI-Powered Development Environments",
5
5
  "main": "dist/index.js",
6
6
  "bin": {