cerber-core 1.0.0

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 (67) hide show
  1. package/.cerber-example/BIBLE.md +132 -0
  2. package/.cerber-example/CERBER_LAW.md +200 -0
  3. package/.cerber-example/connections/contracts/booking-to-pricing.json +44 -0
  4. package/.cerber-example/connections/contracts/pricing-to-booking.json +37 -0
  5. package/.cerber-example/modules/booking-calendar/MODULE.md +225 -0
  6. package/.cerber-example/modules/booking-calendar/contract.json +106 -0
  7. package/.cerber-example/modules/booking-calendar/dependencies.json +8 -0
  8. package/.cerber-example/modules/pricing-engine/MODULE.md +160 -0
  9. package/.cerber-example/modules/pricing-engine/contract.json +64 -0
  10. package/.cerber-example/modules/pricing-engine/dependencies.json +8 -0
  11. package/CHANGELOG.md +68 -0
  12. package/LICENSE +21 -0
  13. package/README.md +1379 -0
  14. package/bin/cerber +105 -0
  15. package/bin/cerber-focus +31 -0
  16. package/bin/cerber-guardian +90 -0
  17. package/bin/cerber-health +113 -0
  18. package/bin/cerber-morning +19 -0
  19. package/bin/cerber-repair +21 -0
  20. package/dist/cerber/index.d.ts +47 -0
  21. package/dist/cerber/index.d.ts.map +1 -0
  22. package/dist/cerber/index.js +154 -0
  23. package/dist/cerber/index.js.map +1 -0
  24. package/dist/guardian/index.d.ts +70 -0
  25. package/dist/guardian/index.d.ts.map +1 -0
  26. package/dist/guardian/index.js +271 -0
  27. package/dist/guardian/index.js.map +1 -0
  28. package/dist/index.d.ts +9 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +9 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/types.d.ts +76 -0
  33. package/dist/types.d.ts.map +1 -0
  34. package/dist/types.js +5 -0
  35. package/dist/types.js.map +1 -0
  36. package/examples/backend-schema.ts +72 -0
  37. package/examples/frontend-schema.ts +67 -0
  38. package/examples/health-checks.ts +196 -0
  39. package/examples/solo-integration/README.md +457 -0
  40. package/examples/solo-integration/package.json +47 -0
  41. package/examples/team-integration/README.md +347 -0
  42. package/examples/team-integration/package.json +23 -0
  43. package/package.json +104 -0
  44. package/solo/README.md +258 -0
  45. package/solo/config/performance-budget.json +53 -0
  46. package/solo/config/solo-contract.json +71 -0
  47. package/solo/lib/feature-flags.ts +177 -0
  48. package/solo/scripts/cerber-auto-repair.js +260 -0
  49. package/solo/scripts/cerber-daily-check.js +282 -0
  50. package/solo/scripts/cerber-dashboard.js +191 -0
  51. package/solo/scripts/cerber-deps-health.js +247 -0
  52. package/solo/scripts/cerber-docs-sync.js +304 -0
  53. package/solo/scripts/cerber-flags-check.js +229 -0
  54. package/solo/scripts/cerber-performance-budget.js +271 -0
  55. package/solo/scripts/cerber-rollback.js +229 -0
  56. package/solo/scripts/cerber-snapshot.js +319 -0
  57. package/team/README.md +327 -0
  58. package/team/config/team-contract.json +27 -0
  59. package/team/lib/module-system.ts +157 -0
  60. package/team/scripts/cerber-add-module.sh +195 -0
  61. package/team/scripts/cerber-connections-check.sh +186 -0
  62. package/team/scripts/cerber-focus.sh +170 -0
  63. package/team/scripts/cerber-module-check.sh +165 -0
  64. package/team/scripts/cerber-team-morning.sh +210 -0
  65. package/team/templates/BIBLE_TEMPLATE.md +52 -0
  66. package/team/templates/CONNECTION_TEMPLATE.json +20 -0
  67. package/team/templates/MODULE_TEMPLATE.md +60 -0
@@ -0,0 +1,304 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Cerber SOLO - Documentation Sync Validator
5
+ *
6
+ * Extends Cerber Core with automation for solo developers
7
+ *
8
+ * Validates:
9
+ * - Extract API endpoints from code
10
+ * - Compare with README
11
+ * - Find ENV vars in code vs docs
12
+ * - Detect stale documentation
13
+ *
14
+ * @author Stefan Pitek
15
+ * @copyright 2026 Stefan Pitek
16
+ * @license MIT
17
+ */
18
+
19
+ const fs = require('fs');
20
+ const path = require('path');
21
+ const { execSync } = require('child_process');
22
+
23
+ console.log('📚 Cerber SOLO - Documentation Sync Validator\n');
24
+
25
+ const issues = [];
26
+
27
+ /**
28
+ * Extract API endpoints from code
29
+ */
30
+ function extractAPIEndpoints() {
31
+ console.log('🔍 Extracting API endpoints from code...\n');
32
+
33
+ try {
34
+ // Find app.get, app.post, router.get, router.post patterns
35
+ const patterns = [
36
+ 'app\\.get\\(',
37
+ 'app\\.post\\(',
38
+ 'app\\.put\\(',
39
+ 'app\\.delete\\(',
40
+ 'router\\.get\\(',
41
+ 'router\\.post\\(',
42
+ 'router\\.put\\(',
43
+ 'router\\.delete\\('
44
+ ];
45
+
46
+ const endpoints = new Set();
47
+
48
+ patterns.forEach(pattern => {
49
+ try {
50
+ const cmd = `grep -r "${pattern}" --include="*.ts" --include="*.js" . 2>/dev/null || true`;
51
+ const results = execSync(cmd, { encoding: 'utf8', maxBuffer: 10 * 1024 * 1024 });
52
+
53
+ if (results) {
54
+ // Extract endpoint paths
55
+ const pathRegex = /['"]([\/][^'"]+)['"]/g;
56
+ let match;
57
+ while ((match = pathRegex.exec(results)) !== null) {
58
+ endpoints.add(match[1]);
59
+ }
60
+ }
61
+ } catch (error) {
62
+ // Continue on error
63
+ }
64
+ });
65
+
66
+ if (endpoints.size > 0) {
67
+ console.log(` ✅ Found ${endpoints.size} API endpoints in code:`);
68
+ Array.from(endpoints).slice(0, 10).forEach(endpoint => {
69
+ console.log(` ${endpoint}`);
70
+ });
71
+ if (endpoints.size > 10) {
72
+ console.log(` ... and ${endpoints.size - 10} more`);
73
+ }
74
+ } else {
75
+ console.log(' â„šī¸ No API endpoints found in code');
76
+ }
77
+
78
+ return endpoints;
79
+ } catch (error) {
80
+ console.log(` âš ī¸ Error extracting endpoints: ${error.message}`);
81
+ return new Set();
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Check if endpoints are documented in README
87
+ */
88
+ function checkEndpointsInReadme(endpoints) {
89
+ console.log('\n📖 Checking README for endpoint documentation...\n');
90
+
91
+ const readmePath = path.join(process.cwd(), 'README.md');
92
+
93
+ if (!fs.existsSync(readmePath)) {
94
+ console.log(' âš ī¸ No README.md found');
95
+ issues.push({
96
+ type: 'missing-readme',
97
+ severity: 'high',
98
+ message: 'README.md not found'
99
+ });
100
+ return;
101
+ }
102
+
103
+ try {
104
+ const readme = fs.readFileSync(readmePath, 'utf8');
105
+ const undocumented = [];
106
+
107
+ endpoints.forEach(endpoint => {
108
+ if (!readme.includes(endpoint)) {
109
+ undocumented.push(endpoint);
110
+ }
111
+ });
112
+
113
+ if (undocumented.length > 0) {
114
+ console.log(` âš ī¸ ${undocumented.length} endpoints not documented in README:`);
115
+ undocumented.slice(0, 5).forEach(endpoint => {
116
+ console.log(` - ${endpoint}`);
117
+ });
118
+ if (undocumented.length > 5) {
119
+ console.log(` ... and ${undocumented.length - 5} more`);
120
+ }
121
+
122
+ issues.push({
123
+ type: 'undocumented-endpoints',
124
+ severity: 'moderate',
125
+ message: `${undocumented.length} endpoints missing from README`,
126
+ endpoints: undocumented
127
+ });
128
+ } else if (endpoints.size > 0) {
129
+ console.log(' ✅ All endpoints are documented in README');
130
+ }
131
+ } catch (error) {
132
+ console.log(` ❌ Error reading README: ${error.message}`);
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Extract environment variables from code
138
+ */
139
+ function extractEnvVars() {
140
+ console.log('\n🔐 Extracting environment variables from code...\n');
141
+
142
+ try {
143
+ const cmd = `grep -r "process\\.env\\." --include="*.ts" --include="*.js" . 2>/dev/null || true`;
144
+ const results = execSync(cmd, { encoding: 'utf8', maxBuffer: 10 * 1024 * 1024 });
145
+
146
+ const envVars = new Set();
147
+ const envRegex = /process\.env\.([A-Z_][A-Z0-9_]*)/g;
148
+
149
+ let match;
150
+ while ((match = envRegex.exec(results)) !== null) {
151
+ envVars.add(match[1]);
152
+ }
153
+
154
+ if (envVars.size > 0) {
155
+ console.log(` ✅ Found ${envVars.size} environment variables in code:`);
156
+ Array.from(envVars).slice(0, 10).forEach(varName => {
157
+ console.log(` ${varName}`);
158
+ });
159
+ if (envVars.size > 10) {
160
+ console.log(` ... and ${envVars.size - 10} more`);
161
+ }
162
+ } else {
163
+ console.log(' â„šī¸ No environment variables found');
164
+ }
165
+
166
+ return envVars;
167
+ } catch (error) {
168
+ console.log(` âš ī¸ Error extracting env vars: ${error.message}`);
169
+ return new Set();
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Check if env vars are documented
175
+ */
176
+ function checkEnvVarsInDocs(envVars) {
177
+ console.log('\n📝 Checking environment variable documentation...\n');
178
+
179
+ const readmePath = path.join(process.cwd(), 'README.md');
180
+ const envExamplePath = path.join(process.cwd(), '.env.example');
181
+
182
+ let readme = '';
183
+ let envExample = '';
184
+
185
+ if (fs.existsSync(readmePath)) {
186
+ readme = fs.readFileSync(readmePath, 'utf8');
187
+ }
188
+
189
+ if (fs.existsSync(envExamplePath)) {
190
+ envExample = fs.readFileSync(envExamplePath, 'utf8');
191
+ }
192
+
193
+ const undocumented = [];
194
+ const missingFromExample = [];
195
+
196
+ envVars.forEach(varName => {
197
+ if (!readme.includes(varName)) {
198
+ undocumented.push(varName);
199
+ }
200
+ if (!envExample.includes(varName)) {
201
+ missingFromExample.push(varName);
202
+ }
203
+ });
204
+
205
+ if (undocumented.length > 0) {
206
+ console.log(` âš ī¸ ${undocumented.length} env vars not in README:`);
207
+ undocumented.slice(0, 5).forEach(varName => {
208
+ console.log(` - ${varName}`);
209
+ });
210
+ if (undocumented.length > 5) {
211
+ console.log(` ... and ${undocumented.length - 5} more`);
212
+ }
213
+
214
+ issues.push({
215
+ type: 'undocumented-env-vars',
216
+ severity: 'low',
217
+ message: `${undocumented.length} env vars not documented`,
218
+ vars: undocumented
219
+ });
220
+ }
221
+
222
+ if (missingFromExample.length > 0) {
223
+ console.log(`\n âš ī¸ ${missingFromExample.length} env vars not in .env.example:`);
224
+ missingFromExample.slice(0, 5).forEach(varName => {
225
+ console.log(` - ${varName}`);
226
+ });
227
+ if (missingFromExample.length > 5) {
228
+ console.log(` ... and ${missingFromExample.length - 5} more`);
229
+ }
230
+
231
+ issues.push({
232
+ type: 'missing-env-example',
233
+ severity: 'moderate',
234
+ message: `${missingFromExample.length} env vars not in .env.example`,
235
+ vars: missingFromExample
236
+ });
237
+ }
238
+
239
+ if (undocumented.length === 0 && missingFromExample.length === 0 && envVars.size > 0) {
240
+ console.log(' ✅ All env vars are documented');
241
+ }
242
+ }
243
+
244
+ /**
245
+ * Check for TODO and FIXME comments
246
+ */
247
+ function checkTodoComments() {
248
+ console.log('\n📌 Checking for TODO/FIXME comments...\n');
249
+
250
+ try {
251
+ const cmd = `grep -rn "TODO\\|FIXME" --include="*.ts" --include="*.js" --include="*.md" . 2>/dev/null || true`;
252
+ const results = execSync(cmd, { encoding: 'utf8', maxBuffer: 10 * 1024 * 1024 });
253
+
254
+ if (results) {
255
+ const lines = results.split('\n').filter(line => line.trim());
256
+ console.log(` â„šī¸ Found ${lines.length} TODO/FIXME comments:`);
257
+ lines.slice(0, 5).forEach(line => {
258
+ console.log(` ${line.substring(0, 80)}${line.length > 80 ? '...' : ''}`);
259
+ });
260
+ if (lines.length > 5) {
261
+ console.log(` ... and ${lines.length - 5} more`);
262
+ }
263
+ } else {
264
+ console.log(' ✅ No TODO/FIXME comments found');
265
+ }
266
+ } catch (error) {
267
+ // Continue on error
268
+ }
269
+ }
270
+
271
+ // Run all checks
272
+ const endpoints = extractAPIEndpoints();
273
+ checkEndpointsInReadme(endpoints);
274
+
275
+ const envVars = extractEnvVars();
276
+ checkEnvVarsInDocs(envVars);
277
+
278
+ checkTodoComments();
279
+
280
+ // Summary
281
+ console.log('\n' + '='.repeat(60));
282
+
283
+ if (issues.length > 0) {
284
+ console.log('\n📋 Documentation Sync Report\n');
285
+ console.log(`Issues found: ${issues.length}\n`);
286
+
287
+ issues.forEach((issue, idx) => {
288
+ const severityEmoji = issue.severity === 'high' ? '🔴' :
289
+ issue.severity === 'moderate' ? '🟡' : 'đŸ”ĩ';
290
+ console.log(`${idx + 1}. ${severityEmoji} [${issue.severity.toUpperCase()}] ${issue.message}`);
291
+ });
292
+
293
+ console.log('\n💡 Recommended Actions:');
294
+ console.log(' 1. Update README.md with missing endpoints');
295
+ console.log(' 2. Add missing vars to .env.example');
296
+ console.log(' 3. Document environment variables');
297
+ console.log(' 4. Run: npm run cerber:repair (to auto-sync .env.example)');
298
+ } else {
299
+ console.log('\n✅ Documentation is in sync!\n');
300
+ }
301
+
302
+ console.log('\n' + '='.repeat(60));
303
+
304
+ process.exit(issues.length > 0 ? 1 : 0);
@@ -0,0 +1,229 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Cerber SOLO - Feature Flags Checker
5
+ *
6
+ * Extends Cerber Core with automation for solo developers
7
+ *
8
+ * Features:
9
+ * - List active flags
10
+ * - Detect expired flags
11
+ * - Per-environment status
12
+ * - Cleanup suggestions
13
+ *
14
+ * @author Stefan Pitek
15
+ * @copyright 2026 Stefan Pitek
16
+ * @license MIT
17
+ */
18
+
19
+ const fs = require('fs');
20
+ const path = require('path');
21
+
22
+ console.log('🚩 Cerber SOLO - Feature Flags Checker\n');
23
+
24
+ /**
25
+ * Find feature flag files
26
+ */
27
+ function findFeatureFlagFiles() {
28
+ const possiblePaths = [
29
+ 'solo/lib/feature-flags.ts',
30
+ 'src/lib/feature-flags.ts',
31
+ 'lib/feature-flags.ts',
32
+ 'src/config/feature-flags.ts',
33
+ 'config/feature-flags.ts',
34
+ 'src/features/flags.ts'
35
+ ];
36
+
37
+ const found = [];
38
+
39
+ possiblePaths.forEach(p => {
40
+ const fullPath = path.join(process.cwd(), p);
41
+ if (fs.existsSync(fullPath)) {
42
+ found.push(fullPath);
43
+ }
44
+ });
45
+
46
+ return found;
47
+ }
48
+
49
+ /**
50
+ * Parse feature flags from file
51
+ */
52
+ function parseFeatureFlags(filePath) {
53
+ try {
54
+ const content = fs.readFileSync(filePath, 'utf8');
55
+ const flags = [];
56
+
57
+ // Look for flag definitions (simplified parsing)
58
+ const flagRegex = /['"]([a-z-_]+)['"]\s*:\s*{[\s\S]*?enabled:\s*(true|false)[\s\S]*?}/gi;
59
+ let match;
60
+
61
+ while ((match = flagRegex.exec(content)) !== null) {
62
+ flags.push({
63
+ name: match[1],
64
+ enabled: match[2] === 'true',
65
+ source: filePath
66
+ });
67
+ }
68
+
69
+ // Also look for simple boolean flags
70
+ const simpleFlagRegex = /export\s+const\s+([A-Z_]+)\s*=\s*(true|false)/gi;
71
+
72
+ while ((match = simpleFlagRegex.exec(content)) !== null) {
73
+ flags.push({
74
+ name: match[1],
75
+ enabled: match[2] === 'true',
76
+ source: filePath
77
+ });
78
+ }
79
+
80
+ return flags;
81
+ } catch (error) {
82
+ console.log(`âš ī¸ Error parsing ${filePath}: ${error.message}`);
83
+ return [];
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Check for expired flags
89
+ */
90
+ function checkExpiredFlags(filePath) {
91
+ try {
92
+ const content = fs.readFileSync(filePath, 'utf8');
93
+ const expired = [];
94
+
95
+ // Look for expiresAt dates
96
+ const expiryRegex = /expiresAt:\s*['"](\d{4}-\d{2}-\d{2})['"]/g;
97
+ let match;
98
+
99
+ const now = new Date();
100
+
101
+ while ((match = expiryRegex.exec(content)) !== null) {
102
+ const expiryDate = new Date(match[1]);
103
+
104
+ if (expiryDate < now) {
105
+ // Find flag name near this expiry
106
+ const before = content.substring(Math.max(0, match.index - 200), match.index);
107
+ const nameMatch = before.match(/['"]([a-z-_]+)['"]\s*:\s*{[^}]*$/i);
108
+
109
+ if (nameMatch) {
110
+ expired.push({
111
+ name: nameMatch[1],
112
+ expiryDate: match[1]
113
+ });
114
+ }
115
+ }
116
+ }
117
+
118
+ return expired;
119
+ } catch (error) {
120
+ return [];
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Find flag usage in codebase
126
+ */
127
+ function findFlagUsage(flagName) {
128
+ try {
129
+ const { execSync } = require('child_process');
130
+ const cmd = `grep -r "${flagName}" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" . 2>/dev/null | wc -l`;
131
+ const count = parseInt(execSync(cmd, { encoding: 'utf8' }).trim());
132
+ return count;
133
+ } catch (error) {
134
+ return 0;
135
+ }
136
+ }
137
+
138
+ // Find and analyze feature flags
139
+ const flagFiles = findFeatureFlagFiles();
140
+
141
+ if (flagFiles.length === 0) {
142
+ console.log('â„šī¸ No feature flag files found\n');
143
+ console.log('Expected locations:');
144
+ console.log(' - solo/lib/feature-flags.ts');
145
+ console.log(' - src/lib/feature-flags.ts');
146
+ console.log(' - src/config/feature-flags.ts\n');
147
+ console.log('💡 Create feature-flags.ts to use this checker');
148
+ process.exit(0);
149
+ }
150
+
151
+ console.log(`📁 Found ${flagFiles.length} feature flag file(s):\n`);
152
+
153
+ let totalFlags = 0;
154
+ let enabledFlags = 0;
155
+ let disabledFlags = 0;
156
+ let allExpiredFlags = [];
157
+
158
+ flagFiles.forEach(file => {
159
+ const relativePath = path.relative(process.cwd(), file);
160
+ console.log(` ${relativePath}`);
161
+
162
+ const flags = parseFeatureFlags(file);
163
+ const expired = checkExpiredFlags(file);
164
+
165
+ totalFlags += flags.length;
166
+
167
+ flags.forEach(flag => {
168
+ if (flag.enabled) {
169
+ enabledFlags++;
170
+ } else {
171
+ disabledFlags++;
172
+ }
173
+ });
174
+
175
+ allExpiredFlags = allExpiredFlags.concat(expired);
176
+ });
177
+
178
+ console.log();
179
+
180
+ if (totalFlags === 0) {
181
+ console.log('â„šī¸ No feature flags detected in files\n');
182
+ console.log('💡 Define flags in your feature-flags.ts file:\n');
183
+ console.log(' export const FLAGS = {');
184
+ console.log(' "new-feature": { enabled: true, description: "..." },');
185
+ console.log(' "beta-ui": { enabled: false, description: "..." }');
186
+ console.log(' };\n');
187
+ process.exit(0);
188
+ }
189
+
190
+ // Summary
191
+ console.log('📊 Feature Flags Summary\n');
192
+ console.log(` Total flags: ${totalFlags}`);
193
+ console.log(` ✅ Enabled: ${enabledFlags}`);
194
+ console.log(` ❌ Disabled: ${disabledFlags}\n`);
195
+
196
+ // Expired flags
197
+ if (allExpiredFlags.length > 0) {
198
+ console.log('⏰ Expired Flags (cleanup recommended)\n');
199
+ allExpiredFlags.forEach(flag => {
200
+ console.log(` 🔴 ${flag.name} (expired: ${flag.expiryDate})`);
201
+ });
202
+ console.log();
203
+ }
204
+
205
+ // Environment detection
206
+ console.log('🌍 Environment Detection\n');
207
+ const env = process.env.NODE_ENV || 'development';
208
+ console.log(` Current environment: ${env}\n`);
209
+
210
+ // Recommendations
211
+ console.log('💡 Recommendations\n');
212
+
213
+ if (allExpiredFlags.length > 0) {
214
+ console.log(' 1. Remove expired feature flags from code');
215
+ console.log(' 2. Clean up flag-related code branches');
216
+ }
217
+
218
+ if (disabledFlags > enabledFlags * 2) {
219
+ console.log(' 3. Review disabled flags - can any be removed?');
220
+ }
221
+
222
+ if (totalFlags > 20) {
223
+ console.log(' 4. Consider flag cleanup - you have many flags');
224
+ }
225
+
226
+ console.log();
227
+ console.log('='.repeat(60));
228
+
229
+ process.exit(allExpiredFlags.length > 0 ? 1 : 0);