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.
- package/.cerber-example/BIBLE.md +132 -0
- package/.cerber-example/CERBER_LAW.md +200 -0
- package/.cerber-example/connections/contracts/booking-to-pricing.json +44 -0
- package/.cerber-example/connections/contracts/pricing-to-booking.json +37 -0
- package/.cerber-example/modules/booking-calendar/MODULE.md +225 -0
- package/.cerber-example/modules/booking-calendar/contract.json +106 -0
- package/.cerber-example/modules/booking-calendar/dependencies.json +8 -0
- package/.cerber-example/modules/pricing-engine/MODULE.md +160 -0
- package/.cerber-example/modules/pricing-engine/contract.json +64 -0
- package/.cerber-example/modules/pricing-engine/dependencies.json +8 -0
- package/CHANGELOG.md +68 -0
- package/LICENSE +21 -0
- package/README.md +1379 -0
- package/bin/cerber +105 -0
- package/bin/cerber-focus +31 -0
- package/bin/cerber-guardian +90 -0
- package/bin/cerber-health +113 -0
- package/bin/cerber-morning +19 -0
- package/bin/cerber-repair +21 -0
- package/dist/cerber/index.d.ts +47 -0
- package/dist/cerber/index.d.ts.map +1 -0
- package/dist/cerber/index.js +154 -0
- package/dist/cerber/index.js.map +1 -0
- package/dist/guardian/index.d.ts +70 -0
- package/dist/guardian/index.d.ts.map +1 -0
- package/dist/guardian/index.js +271 -0
- package/dist/guardian/index.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/examples/backend-schema.ts +72 -0
- package/examples/frontend-schema.ts +67 -0
- package/examples/health-checks.ts +196 -0
- package/examples/solo-integration/README.md +457 -0
- package/examples/solo-integration/package.json +47 -0
- package/examples/team-integration/README.md +347 -0
- package/examples/team-integration/package.json +23 -0
- package/package.json +104 -0
- package/solo/README.md +258 -0
- package/solo/config/performance-budget.json +53 -0
- package/solo/config/solo-contract.json +71 -0
- package/solo/lib/feature-flags.ts +177 -0
- package/solo/scripts/cerber-auto-repair.js +260 -0
- package/solo/scripts/cerber-daily-check.js +282 -0
- package/solo/scripts/cerber-dashboard.js +191 -0
- package/solo/scripts/cerber-deps-health.js +247 -0
- package/solo/scripts/cerber-docs-sync.js +304 -0
- package/solo/scripts/cerber-flags-check.js +229 -0
- package/solo/scripts/cerber-performance-budget.js +271 -0
- package/solo/scripts/cerber-rollback.js +229 -0
- package/solo/scripts/cerber-snapshot.js +319 -0
- package/team/README.md +327 -0
- package/team/config/team-contract.json +27 -0
- package/team/lib/module-system.ts +157 -0
- package/team/scripts/cerber-add-module.sh +195 -0
- package/team/scripts/cerber-connections-check.sh +186 -0
- package/team/scripts/cerber-focus.sh +170 -0
- package/team/scripts/cerber-module-check.sh +165 -0
- package/team/scripts/cerber-team-morning.sh +210 -0
- package/team/templates/BIBLE_TEMPLATE.md +52 -0
- package/team/templates/CONNECTION_TEMPLATE.json +20 -0
- package/team/templates/MODULE_TEMPLATE.md +60 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cerber SOLO - Auto-Repair System
|
|
5
|
+
*
|
|
6
|
+
* Extends Cerber Core with automation for solo developers
|
|
7
|
+
*
|
|
8
|
+
* Automatically fixes common issues:
|
|
9
|
+
* - Format package.json (sort scripts and deps)
|
|
10
|
+
* - Sync .env.example (add missing environment variable keys)
|
|
11
|
+
* - Auto-generate CHANGELOG (from git log)
|
|
12
|
+
* - Remove console.logs (with approval system)
|
|
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
|
+
// Parse command line arguments
|
|
24
|
+
const args = process.argv.slice(2);
|
|
25
|
+
const isDryRun = args.includes('--dry-run');
|
|
26
|
+
const requiresApproval = args.includes('--approve');
|
|
27
|
+
|
|
28
|
+
console.log('š§ Cerber SOLO - Auto-Repair System\n');
|
|
29
|
+
console.log(`Mode: ${isDryRun ? 'DRY RUN' : 'LIVE'}\n`);
|
|
30
|
+
|
|
31
|
+
let changesCount = 0;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Format and sort package.json
|
|
35
|
+
*/
|
|
36
|
+
function formatPackageJson() {
|
|
37
|
+
console.log('š¦ Checking package.json...');
|
|
38
|
+
|
|
39
|
+
const packagePath = path.join(process.cwd(), 'package.json');
|
|
40
|
+
|
|
41
|
+
if (!fs.existsSync(packagePath)) {
|
|
42
|
+
console.log(' ā ļø No package.json found, skipping');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const packageData = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
|
48
|
+
|
|
49
|
+
// Sort scripts alphabetically
|
|
50
|
+
if (packageData.scripts) {
|
|
51
|
+
const sortedScripts = Object.keys(packageData.scripts)
|
|
52
|
+
.sort()
|
|
53
|
+
.reduce((acc, key) => {
|
|
54
|
+
acc[key] = packageData.scripts[key];
|
|
55
|
+
return acc;
|
|
56
|
+
}, {});
|
|
57
|
+
packageData.scripts = sortedScripts;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Sort dependencies
|
|
61
|
+
['dependencies', 'devDependencies', 'peerDependencies'].forEach(depType => {
|
|
62
|
+
if (packageData[depType]) {
|
|
63
|
+
const sorted = Object.keys(packageData[depType])
|
|
64
|
+
.sort()
|
|
65
|
+
.reduce((acc, key) => {
|
|
66
|
+
acc[key] = packageData[depType][key];
|
|
67
|
+
return acc;
|
|
68
|
+
}, {});
|
|
69
|
+
packageData[depType] = sorted;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const formatted = JSON.stringify(packageData, null, 2) + '\n';
|
|
74
|
+
|
|
75
|
+
if (!isDryRun) {
|
|
76
|
+
fs.writeFileSync(packagePath, formatted, 'utf8');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
console.log(' ā
Package.json formatted and sorted');
|
|
80
|
+
changesCount++;
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.log(` ā Error formatting package.json: ${error.message}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Sync .env.example with environment variables used in code
|
|
88
|
+
*/
|
|
89
|
+
function syncEnvExample() {
|
|
90
|
+
console.log('\nš Checking .env.example...');
|
|
91
|
+
|
|
92
|
+
const envExamplePath = path.join(process.cwd(), '.env.example');
|
|
93
|
+
const envPath = path.join(process.cwd(), '.env');
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
// Find all VITE_* and REACT_APP_* variables in source code
|
|
97
|
+
let envVars = new Set();
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
const grepCommand = 'grep -r "VITE_\\|REACT_APP_\\|NEXT_PUBLIC_" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" . 2>/dev/null || true';
|
|
101
|
+
const grepOutput = execSync(grepCommand, { encoding: 'utf8', maxBuffer: 10 * 1024 * 1024 });
|
|
102
|
+
|
|
103
|
+
const envRegex = /(VITE_[A-Z_]+|REACT_APP_[A-Z_]+|NEXT_PUBLIC_[A-Z_]+)/g;
|
|
104
|
+
const matches = grepOutput.match(envRegex);
|
|
105
|
+
|
|
106
|
+
if (matches) {
|
|
107
|
+
matches.forEach(v => envVars.add(v));
|
|
108
|
+
}
|
|
109
|
+
} catch (error) {
|
|
110
|
+
// grep may fail if no files found, that's okay
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (envVars.size === 0) {
|
|
114
|
+
console.log(' ā¹ļø No environment variables found in code');
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Read existing .env.example
|
|
119
|
+
let existingVars = new Set();
|
|
120
|
+
if (fs.existsSync(envExamplePath)) {
|
|
121
|
+
const content = fs.readFileSync(envExamplePath, 'utf8');
|
|
122
|
+
content.split('\n').forEach(line => {
|
|
123
|
+
const match = line.match(/^([A-Z_]+)=/);
|
|
124
|
+
if (match) {
|
|
125
|
+
existingVars.add(match[1]);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Find missing variables
|
|
131
|
+
const missingVars = Array.from(envVars).filter(v => !existingVars.has(v));
|
|
132
|
+
|
|
133
|
+
if (missingVars.length === 0) {
|
|
134
|
+
console.log(' ā
.env.example is up to date');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
console.log(` š Found ${missingVars.length} missing variables: ${missingVars.join(', ')}`);
|
|
139
|
+
|
|
140
|
+
if (!isDryRun) {
|
|
141
|
+
let content = fs.existsSync(envExamplePath) ?
|
|
142
|
+
fs.readFileSync(envExamplePath, 'utf8') : '';
|
|
143
|
+
|
|
144
|
+
if (content && !content.endsWith('\n')) {
|
|
145
|
+
content += '\n';
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
content += '\n# Auto-added by Cerber SOLO\n';
|
|
149
|
+
missingVars.forEach(varName => {
|
|
150
|
+
content += `${varName}=\n`;
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
fs.writeFileSync(envExamplePath, content, 'utf8');
|
|
154
|
+
console.log(' ā
Updated .env.example');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
changesCount++;
|
|
158
|
+
} catch (error) {
|
|
159
|
+
console.log(` ā Error syncing .env.example: ${error.message}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Auto-generate CHANGELOG from git log
|
|
165
|
+
*/
|
|
166
|
+
function generateChangelog() {
|
|
167
|
+
console.log('\nš Checking CHANGELOG...');
|
|
168
|
+
|
|
169
|
+
const changelogPath = path.join(process.cwd(), 'CHANGELOG.md');
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
// Check if git repo exists
|
|
173
|
+
if (!fs.existsSync(path.join(process.cwd(), '.git'))) {
|
|
174
|
+
console.log(' ā ļø Not a git repository, skipping');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Get recent commits
|
|
179
|
+
const gitLog = execSync('git log --pretty=format:"%h - %s (%an, %ar)" -20', {
|
|
180
|
+
encoding: 'utf8',
|
|
181
|
+
maxBuffer: 10 * 1024 * 1024
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
if (!gitLog) {
|
|
185
|
+
console.log(' ā¹ļø No commits found');
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const date = new Date().toISOString().split('T')[0];
|
|
190
|
+
const changelog = `# Changelog\n\n## [Unreleased] - ${date}\n\n### Recent Changes\n\n${gitLog.split('\n').map(line => `- ${line}`).join('\n')}\n\n---\n*Generated by Cerber SOLO*\n`;
|
|
191
|
+
|
|
192
|
+
if (!isDryRun) {
|
|
193
|
+
fs.writeFileSync(changelogPath, changelog, 'utf8');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
console.log(' ā
CHANGELOG generated from git log');
|
|
197
|
+
changesCount++;
|
|
198
|
+
} catch (error) {
|
|
199
|
+
console.log(` ā ļø Error generating CHANGELOG: ${error.message}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Remove console.logs with approval
|
|
205
|
+
*/
|
|
206
|
+
function removeConsoleLogs() {
|
|
207
|
+
console.log('\nš§¹ Checking for console.log statements...');
|
|
208
|
+
|
|
209
|
+
if (!requiresApproval) {
|
|
210
|
+
console.log(' ā¹ļø Use --approve flag to enable console.log removal');
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
const grepCommand = 'grep -rn "console\\.log" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" . 2>/dev/null || true';
|
|
216
|
+
const consoleLogFiles = execSync(grepCommand, {
|
|
217
|
+
encoding: 'utf8',
|
|
218
|
+
maxBuffer: 10 * 1024 * 1024
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
if (!consoleLogFiles) {
|
|
222
|
+
console.log(' ā
No console.log statements found');
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const lines = consoleLogFiles.split('\n').filter(line => line.trim());
|
|
227
|
+
console.log(` š Found ${lines.length} console.log statements`);
|
|
228
|
+
|
|
229
|
+
if (lines.length > 0) {
|
|
230
|
+
console.log(' ā ļø Manual review recommended - showing first 5:');
|
|
231
|
+
lines.slice(0, 5).forEach(line => {
|
|
232
|
+
console.log(` ${line}`);
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
changesCount++;
|
|
237
|
+
} catch (error) {
|
|
238
|
+
// grep may fail if no files found
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Run all repairs
|
|
243
|
+
formatPackageJson();
|
|
244
|
+
syncEnvExample();
|
|
245
|
+
generateChangelog();
|
|
246
|
+
removeConsoleLogs();
|
|
247
|
+
|
|
248
|
+
// Summary
|
|
249
|
+
console.log('\n' + '='.repeat(50));
|
|
250
|
+
console.log(`\n⨠Auto-repair complete!`);
|
|
251
|
+
console.log(` Changes detected: ${changesCount}`);
|
|
252
|
+
console.log(` Mode: ${isDryRun ? 'DRY RUN (no files modified)' : 'LIVE (files updated)'}`);
|
|
253
|
+
|
|
254
|
+
if (isDryRun && changesCount > 0) {
|
|
255
|
+
console.log('\nš” Run without --dry-run to apply changes');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
console.log('\n' + '='.repeat(50));
|
|
259
|
+
|
|
260
|
+
process.exit(0);
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cerber SOLO - Daily Check (Morning Dashboard)
|
|
5
|
+
*
|
|
6
|
+
* Extends Cerber Core with automation for solo developers
|
|
7
|
+
*
|
|
8
|
+
* Checks:
|
|
9
|
+
* - Backend health (via /api/health)
|
|
10
|
+
* - Guardian validation status
|
|
11
|
+
* - Git status
|
|
12
|
+
* - Yesterday's snapshot
|
|
13
|
+
* - Today's priorities
|
|
14
|
+
*
|
|
15
|
+
* @author Stefan Pitek
|
|
16
|
+
* @copyright 2026 Stefan Pitek
|
|
17
|
+
* @license MIT
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const { execSync } = require('child_process');
|
|
21
|
+
const fs = require('fs');
|
|
22
|
+
const path = require('path');
|
|
23
|
+
|
|
24
|
+
console.log('āļø Cerber SOLO - Morning Dashboard\n');
|
|
25
|
+
console.log('='.repeat(60));
|
|
26
|
+
|
|
27
|
+
const date = new Date().toLocaleDateString('en-US', {
|
|
28
|
+
weekday: 'long',
|
|
29
|
+
year: 'numeric',
|
|
30
|
+
month: 'long',
|
|
31
|
+
day: 'numeric'
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
console.log(`\nš
${date}\n`);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Check backend health
|
|
38
|
+
*/
|
|
39
|
+
function checkBackendHealth() {
|
|
40
|
+
console.log('š„ Backend Health Check\n');
|
|
41
|
+
|
|
42
|
+
const healthUrls = [
|
|
43
|
+
'http://localhost:3000/api/health',
|
|
44
|
+
'http://localhost:4000/api/health',
|
|
45
|
+
'http://localhost:5000/api/health'
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
let healthChecked = false;
|
|
49
|
+
|
|
50
|
+
for (const url of healthUrls) {
|
|
51
|
+
try {
|
|
52
|
+
// Try with curl (available on most systems)
|
|
53
|
+
const response = execSync(`curl -s -m 2 ${url} 2>/dev/null || true`, {
|
|
54
|
+
encoding: 'utf8',
|
|
55
|
+
timeout: 3000
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
if (response && response.includes('status')) {
|
|
59
|
+
const data = JSON.parse(response);
|
|
60
|
+
const status = data.status || 'unknown';
|
|
61
|
+
const emoji = status === 'healthy' ? 'ā
' : status === 'degraded' ? 'ā ļø' : 'š“';
|
|
62
|
+
|
|
63
|
+
console.log(` ${emoji} ${url}: ${status}`);
|
|
64
|
+
|
|
65
|
+
if (data.summary) {
|
|
66
|
+
const s = data.summary;
|
|
67
|
+
if (s.criticalIssues > 0) console.log(` š“ Critical: ${s.criticalIssues}`);
|
|
68
|
+
if (s.errorIssues > 0) console.log(` š Errors: ${s.errorIssues}`);
|
|
69
|
+
if (s.warningIssues > 0) console.log(` š” Warnings: ${s.warningIssues}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
healthChecked = true;
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
} catch (error) {
|
|
76
|
+
// Continue to next URL
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!healthChecked) {
|
|
81
|
+
console.log(' ā¹ļø Backend not running or health endpoint not accessible');
|
|
82
|
+
console.log(' š” Start your server to enable health checks');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
console.log();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Check Guardian validation status
|
|
90
|
+
*/
|
|
91
|
+
function checkGuardianStatus() {
|
|
92
|
+
console.log('š”ļø Guardian Status\n');
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
// Check if Guardian validation script exists
|
|
96
|
+
const guardianPaths = [
|
|
97
|
+
'scripts/validate-schema.mjs',
|
|
98
|
+
'scripts/validate-schema.js',
|
|
99
|
+
'.husky/pre-commit'
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
const guardianExists = guardianPaths.some(p =>
|
|
103
|
+
fs.existsSync(path.join(process.cwd(), p))
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
if (guardianExists) {
|
|
107
|
+
console.log(' ā
Guardian is installed');
|
|
108
|
+
|
|
109
|
+
// Check recent commits
|
|
110
|
+
try {
|
|
111
|
+
const recentCommits = execSync('git log --oneline -5', { encoding: 'utf8' });
|
|
112
|
+
console.log(' š Recent commits passed validation:\n');
|
|
113
|
+
recentCommits.split('\n').slice(0, 3).forEach(commit => {
|
|
114
|
+
if (commit.trim()) {
|
|
115
|
+
console.log(` ${commit}`);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
} catch (error) {
|
|
119
|
+
// Not a git repo
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
console.log(' ā ļø Guardian not detected');
|
|
123
|
+
console.log(' š” Consider setting up Guardian for pre-commit validation');
|
|
124
|
+
}
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.log(` ā ļø Error checking Guardian: ${error.message}`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
console.log();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Check Git status
|
|
134
|
+
*/
|
|
135
|
+
function checkGitStatus() {
|
|
136
|
+
console.log('š Git Status\n');
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
const status = execSync('git status --short', { encoding: 'utf8' });
|
|
140
|
+
|
|
141
|
+
if (status.trim()) {
|
|
142
|
+
const lines = status.split('\n').filter(l => l.trim());
|
|
143
|
+
console.log(` š ${lines.length} file(s) with changes:\n`);
|
|
144
|
+
|
|
145
|
+
lines.slice(0, 10).forEach(line => {
|
|
146
|
+
const statusCode = line.substring(0, 2).trim();
|
|
147
|
+
const file = line.substring(3);
|
|
148
|
+
const emoji = statusCode.includes('M') ? 'š' :
|
|
149
|
+
statusCode.includes('A') ? 'āØ' :
|
|
150
|
+
statusCode.includes('D') ? 'šļø' :
|
|
151
|
+
statusCode.includes('?') ? 'ā' : 'š';
|
|
152
|
+
console.log(` ${emoji} ${file}`);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
if (lines.length > 10) {
|
|
156
|
+
console.log(` ... and ${lines.length - 10} more`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Check branch
|
|
160
|
+
const branch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim();
|
|
161
|
+
console.log(`\n šæ Branch: ${branch}`);
|
|
162
|
+
|
|
163
|
+
// Check unpushed commits
|
|
164
|
+
try {
|
|
165
|
+
const unpushed = execSync('git log @{u}.. --oneline 2>/dev/null || true', { encoding: 'utf8' });
|
|
166
|
+
if (unpushed.trim()) {
|
|
167
|
+
const count = unpushed.split('\n').filter(l => l.trim()).length;
|
|
168
|
+
console.log(` ā¬ļø ${count} unpushed commit(s)`);
|
|
169
|
+
}
|
|
170
|
+
} catch (error) {
|
|
171
|
+
// No upstream branch
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
console.log(' ā
Working directory clean');
|
|
175
|
+
|
|
176
|
+
const branch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim();
|
|
177
|
+
console.log(` šæ Branch: ${branch}`);
|
|
178
|
+
}
|
|
179
|
+
} catch (error) {
|
|
180
|
+
console.log(' ā¹ļø Not a git repository');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
console.log();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Check yesterday's snapshot
|
|
188
|
+
*/
|
|
189
|
+
function checkSnapshot() {
|
|
190
|
+
console.log('šø Yesterday\'s Snapshot\n');
|
|
191
|
+
|
|
192
|
+
const snapshotDir = path.join(process.cwd(), '.cerber', 'snapshots');
|
|
193
|
+
|
|
194
|
+
if (!fs.existsSync(snapshotDir)) {
|
|
195
|
+
console.log(' ā¹ļø No snapshots found');
|
|
196
|
+
console.log(' š” Run: npm run cerber:snapshot (to create daily snapshots)');
|
|
197
|
+
console.log();
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
const files = fs.readdirSync(snapshotDir).sort().reverse();
|
|
203
|
+
|
|
204
|
+
if (files.length === 0) {
|
|
205
|
+
console.log(' ā¹ļø No snapshots found');
|
|
206
|
+
console.log();
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Get most recent snapshot
|
|
211
|
+
const latest = files[0];
|
|
212
|
+
const snapshotPath = path.join(snapshotDir, latest);
|
|
213
|
+
const snapshot = JSON.parse(fs.readFileSync(snapshotPath, 'utf8'));
|
|
214
|
+
|
|
215
|
+
console.log(` š
Latest snapshot: ${latest.replace('.json', '')}`);
|
|
216
|
+
console.log(` š Commits: ${snapshot.commits || 0}`);
|
|
217
|
+
console.log(` š Files changed: ${snapshot.filesChanged || 0}`);
|
|
218
|
+
console.log(` š Lines added: ${snapshot.linesAdded || 0}`);
|
|
219
|
+
console.log(` š Lines removed: ${snapshot.linesRemoved || 0}`);
|
|
220
|
+
} catch (error) {
|
|
221
|
+
console.log(` ā ļø Error reading snapshot: ${error.message}`);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
console.log();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Show today's priorities
|
|
229
|
+
*/
|
|
230
|
+
function showPriorities() {
|
|
231
|
+
console.log('šÆ Today\'s Priorities\n');
|
|
232
|
+
|
|
233
|
+
// Check for TODO comments in recently modified files
|
|
234
|
+
try {
|
|
235
|
+
const recentFiles = execSync('git diff --name-only HEAD~1..HEAD 2>/dev/null || true', {
|
|
236
|
+
encoding: 'utf8'
|
|
237
|
+
}).trim();
|
|
238
|
+
|
|
239
|
+
if (recentFiles) {
|
|
240
|
+
console.log(' š Recently modified files:');
|
|
241
|
+
recentFiles.split('\n').slice(0, 5).forEach(file => {
|
|
242
|
+
console.log(` - ${file}`);
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
} catch (error) {
|
|
246
|
+
// Continue
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
console.log('\n š” Suggested workflow:');
|
|
250
|
+
console.log(' 1. Review git status');
|
|
251
|
+
console.log(' 2. Run: npm run cerber:repair (auto-fix issues)');
|
|
252
|
+
console.log(' 3. Run: npm run cerber:deps (check dependencies)');
|
|
253
|
+
console.log(' 4. Code your features');
|
|
254
|
+
console.log(' 5. Run: npm run cerber:pre-push (before pushing)');
|
|
255
|
+
console.log(' 6. Run: npm run cerber:snapshot (end of day)\n');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Quick actions menu
|
|
260
|
+
*/
|
|
261
|
+
function showQuickActions() {
|
|
262
|
+
console.log('ā” Quick Actions\n');
|
|
263
|
+
console.log(' npm run cerber:repair # Auto-fix issues');
|
|
264
|
+
console.log(' npm run cerber:deps # Check dependencies');
|
|
265
|
+
console.log(' npm run cerber:docs # Sync documentation');
|
|
266
|
+
console.log(' npm run cerber:perf # Check performance');
|
|
267
|
+
console.log(' npm run cerber:flags # Check feature flags');
|
|
268
|
+
console.log();
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Run all checks
|
|
272
|
+
checkBackendHealth();
|
|
273
|
+
checkGuardianStatus();
|
|
274
|
+
checkGitStatus();
|
|
275
|
+
checkSnapshot();
|
|
276
|
+
showPriorities();
|
|
277
|
+
showQuickActions();
|
|
278
|
+
|
|
279
|
+
console.log('='.repeat(60));
|
|
280
|
+
console.log('\n⨠Have a productive day!\n');
|
|
281
|
+
|
|
282
|
+
process.exit(0);
|