faf-cli 4.3.0 ā 4.3.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.
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +40 -22
- package/dist/cli.js.map +1 -1
- package/dist/commands/readme.d.ts +11 -6
- package/dist/commands/readme.d.ts.map +1 -1
- package/dist/commands/readme.js +167 -120
- package/dist/commands/readme.js.map +1 -1
- package/dist/commands/show.d.ts.map +1 -1
- package/dist/commands/show.js +22 -7
- package/dist/commands/show.js.map +1 -1
- package/dist/commands/sixws.d.ts +6 -0
- package/dist/commands/sixws.d.ts.map +1 -0
- package/dist/commands/sixws.js +154 -0
- package/dist/commands/sixws.js.map +1 -0
- package/dist/utils/file-utils.d.ts.map +1 -1
- package/dist/utils/file-utils.js +1 -4
- package/dist/utils/file-utils.js.map +1 -1
- package/package.json +5 -2
- package/project.faf +4 -4
- package/scripts/ANTHROPIC-DEMO.sh +203 -0
- package/scripts/boris-ready.sh +169 -0
- package/scripts/bundle-yaml.js +87 -0
- package/scripts/check-version.js +88 -0
- package/scripts/clean-build.js +34 -0
- package/scripts/cleanup-unused.sh +54 -0
- package/scripts/debug-django.txt +9 -0
- package/scripts/debug-mongo.txt +9 -0
- package/scripts/debug-react.txt +9 -0
- package/scripts/debug-rust.txt +9 -0
- package/scripts/debug-whisper.cpp.txt +9 -0
- package/scripts/evaluate-family-member.ts +300 -0
- package/scripts/generate-docs.ts +358 -0
- package/scripts/generate-drift-reports.sh +111 -0
- package/scripts/industry-showcase.json +122 -0
- package/scripts/mcp-ecosystem-research.sh +58 -0
- package/scripts/migrate-yaml-imports.sh +55 -0
- package/scripts/migrate-yaml.ts +132 -0
- package/scripts/performance-validation.ts +460 -0
- package/scripts/postinstall.js +30 -0
- package/scripts/prepare-release.ts +421 -0
- package/scripts/run-industry-showcase.ts +237 -0
- package/scripts/run-test-showcase.ts +244 -0
- package/scripts/setup-github-watch.sh +43 -0
- package/scripts/sync-version.js +35 -0
- package/scripts/test-integration-detection.ts +93 -0
- package/scripts/test-integration-simple.js +93 -0
- package/scripts/test-medal-progression.sh +143 -0
- package/scripts/test-showcase-results.json +109 -0
- package/scripts/test-showcase.json +32 -0
- package/scripts/update-version.js +148 -0
- package/scripts/verify-build.js +343 -0
- package/scripts/version-check.js +78 -0
- package/scripts/watch-discussions.sh +86 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
{
|
|
2
|
+
"generated": "2026-02-09T01:39:39.488Z",
|
|
3
|
+
"totalRepos": 5,
|
|
4
|
+
"successCount": 0,
|
|
5
|
+
"failedCount": 5,
|
|
6
|
+
"avgImprovement": 0,
|
|
7
|
+
"categories": [
|
|
8
|
+
{
|
|
9
|
+
"name": "JavaScript/TypeScript",
|
|
10
|
+
"repos": [
|
|
11
|
+
{
|
|
12
|
+
"repo": "facebook/react",
|
|
13
|
+
"owner": "facebook",
|
|
14
|
+
"name": "react",
|
|
15
|
+
"category": "JavaScript/TypeScript",
|
|
16
|
+
"currentScore": 0,
|
|
17
|
+
"newScore": 0,
|
|
18
|
+
"improvement": 0,
|
|
19
|
+
"tier": "Failed",
|
|
20
|
+
"stack": {},
|
|
21
|
+
"projectType": "unknown",
|
|
22
|
+
"mainLanguage": "unknown",
|
|
23
|
+
"description": "",
|
|
24
|
+
"status": "failed",
|
|
25
|
+
"error": "Failed to parse output (saved to /Users/wolfejam/FAF/cli/scripts/debug-react.txt)"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "Python",
|
|
31
|
+
"repos": [
|
|
32
|
+
{
|
|
33
|
+
"repo": "django/django",
|
|
34
|
+
"owner": "django",
|
|
35
|
+
"name": "django",
|
|
36
|
+
"category": "Python",
|
|
37
|
+
"currentScore": 0,
|
|
38
|
+
"newScore": 0,
|
|
39
|
+
"improvement": 0,
|
|
40
|
+
"tier": "Failed",
|
|
41
|
+
"stack": {},
|
|
42
|
+
"projectType": "unknown",
|
|
43
|
+
"mainLanguage": "unknown",
|
|
44
|
+
"description": "",
|
|
45
|
+
"status": "failed",
|
|
46
|
+
"error": "Failed to parse output (saved to /Users/wolfejam/FAF/cli/scripts/debug-django.txt)"
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "Systems/Low-level",
|
|
52
|
+
"repos": [
|
|
53
|
+
{
|
|
54
|
+
"repo": "ggml-org/whisper.cpp",
|
|
55
|
+
"owner": "ggml-org",
|
|
56
|
+
"name": "whisper.cpp",
|
|
57
|
+
"category": "Systems/Low-level",
|
|
58
|
+
"currentScore": 0,
|
|
59
|
+
"newScore": 0,
|
|
60
|
+
"improvement": 0,
|
|
61
|
+
"tier": "Failed",
|
|
62
|
+
"stack": {},
|
|
63
|
+
"projectType": "unknown",
|
|
64
|
+
"mainLanguage": "unknown",
|
|
65
|
+
"description": "",
|
|
66
|
+
"status": "failed",
|
|
67
|
+
"error": "Failed to parse output (saved to /Users/wolfejam/FAF/cli/scripts/debug-whisper.cpp.txt)"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"repo": "rust-lang/rust",
|
|
71
|
+
"owner": "rust-lang",
|
|
72
|
+
"name": "rust",
|
|
73
|
+
"category": "Systems/Low-level",
|
|
74
|
+
"currentScore": 0,
|
|
75
|
+
"newScore": 0,
|
|
76
|
+
"improvement": 0,
|
|
77
|
+
"tier": "Failed",
|
|
78
|
+
"stack": {},
|
|
79
|
+
"projectType": "unknown",
|
|
80
|
+
"mainLanguage": "unknown",
|
|
81
|
+
"description": "",
|
|
82
|
+
"status": "failed",
|
|
83
|
+
"error": "Failed to parse output (saved to /Users/wolfejam/FAF/cli/scripts/debug-rust.txt)"
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"name": "Databases",
|
|
89
|
+
"repos": [
|
|
90
|
+
{
|
|
91
|
+
"repo": "mongodb/mongo",
|
|
92
|
+
"owner": "mongodb",
|
|
93
|
+
"name": "mongo",
|
|
94
|
+
"category": "Databases",
|
|
95
|
+
"currentScore": 0,
|
|
96
|
+
"newScore": 0,
|
|
97
|
+
"improvement": 0,
|
|
98
|
+
"tier": "Failed",
|
|
99
|
+
"stack": {},
|
|
100
|
+
"projectType": "unknown",
|
|
101
|
+
"mainLanguage": "unknown",
|
|
102
|
+
"description": "",
|
|
103
|
+
"status": "failed",
|
|
104
|
+
"error": "Failed to parse output (saved to /Users/wolfejam/FAF/cli/scripts/debug-mongo.txt)"
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "FAF Industry Showcase - Test Run",
|
|
3
|
+
"description": "Small test of 5 diverse repos before full showcase",
|
|
4
|
+
"updated": "2026-02-08",
|
|
5
|
+
"categories": [
|
|
6
|
+
{
|
|
7
|
+
"name": "JavaScript/TypeScript",
|
|
8
|
+
"repos": [
|
|
9
|
+
"facebook/react"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "Python",
|
|
14
|
+
"repos": [
|
|
15
|
+
"django/django"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "Systems/Low-level",
|
|
20
|
+
"repos": [
|
|
21
|
+
"ggml-org/whisper.cpp",
|
|
22
|
+
"rust-lang/rust"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "Databases",
|
|
27
|
+
"repos": [
|
|
28
|
+
"mongodb/mongo"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* šļø Version Update Script - Ensures all version references stay synchronized
|
|
5
|
+
* Run this BEFORE committing any version changes
|
|
6
|
+
* Usage: npm run version:update 2.8.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const glob = require('glob');
|
|
12
|
+
|
|
13
|
+
const VERSION_PATTERN = /v?\d+\.\d+\.\d+/g;
|
|
14
|
+
|
|
15
|
+
// Files that should always have the latest version
|
|
16
|
+
const VERSION_FILES = [
|
|
17
|
+
{
|
|
18
|
+
path: 'package.json',
|
|
19
|
+
pattern: /"version":\s*"[\d.]+"/,
|
|
20
|
+
replacement: (version) => `"version": "${version}"`
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
path: 'src/utils/championship-style.ts',
|
|
24
|
+
patterns: [
|
|
25
|
+
{
|
|
26
|
+
pattern: /FAF CLI v\d+\.\d+\.\d+/g,
|
|
27
|
+
replacement: (version) => `FAF CLI v${version}`
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
pattern: /šļøā”ļøš\s+v\d+\.\d+\.\d+/g,
|
|
31
|
+
replacement: (version) => `šļøā”ļøš v${version}`
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
pattern: /\(v\d+\.\d+\.\d+ [^)]+\)/g,
|
|
35
|
+
replacement: (version) => `(v${version} White Stripe Edition)`
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
// Files that should keep their specific version references (schemas, etc.)
|
|
42
|
+
const IGNORE_PATTERNS = [
|
|
43
|
+
'tests/**/*.test.ts',
|
|
44
|
+
'**/node_modules/**',
|
|
45
|
+
'dist/**',
|
|
46
|
+
'*.md' // Documentation can reference old versions
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
function updateVersion(newVersion) {
|
|
50
|
+
if (!newVersion || !newVersion.match(/^\d+\.\d+\.\d+$/)) {
|
|
51
|
+
console.error('ā Invalid version format. Use: X.Y.Z (e.g., 2.8.0)');
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
console.log(`šļø Updating all version references to v${newVersion}...`);
|
|
56
|
+
|
|
57
|
+
let updatedFiles = [];
|
|
58
|
+
|
|
59
|
+
VERSION_FILES.forEach(file => {
|
|
60
|
+
const filePath = path.join(__dirname, '..', file.path);
|
|
61
|
+
|
|
62
|
+
if (!fs.existsSync(filePath)) {
|
|
63
|
+
console.warn(`ā ļø File not found: ${file.path}`);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let content = fs.readFileSync(filePath, 'utf8');
|
|
68
|
+
let modified = false;
|
|
69
|
+
|
|
70
|
+
if (file.pattern) {
|
|
71
|
+
// Single pattern
|
|
72
|
+
const newContent = content.replace(file.pattern, file.replacement(newVersion));
|
|
73
|
+
if (newContent !== content) {
|
|
74
|
+
content = newContent;
|
|
75
|
+
modified = true;
|
|
76
|
+
}
|
|
77
|
+
} else if (file.patterns) {
|
|
78
|
+
// Multiple patterns
|
|
79
|
+
file.patterns.forEach(patternObj => {
|
|
80
|
+
const newContent = content.replace(patternObj.pattern, patternObj.replacement(newVersion));
|
|
81
|
+
if (newContent !== content) {
|
|
82
|
+
content = newContent;
|
|
83
|
+
modified = true;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (modified) {
|
|
89
|
+
fs.writeFileSync(filePath, content);
|
|
90
|
+
updatedFiles.push(file.path);
|
|
91
|
+
console.log(`ā
Updated: ${file.path}`);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Check for any remaining old versions in critical files
|
|
96
|
+
console.log('\nš Checking for stray version references...');
|
|
97
|
+
|
|
98
|
+
const criticalFiles = glob.sync('src/**/*.ts', {
|
|
99
|
+
ignore: IGNORE_PATTERNS,
|
|
100
|
+
cwd: path.join(__dirname, '..')
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
let strayVersions = [];
|
|
104
|
+
|
|
105
|
+
criticalFiles.forEach(file => {
|
|
106
|
+
const content = fs.readFileSync(path.join(__dirname, '..', file), 'utf8');
|
|
107
|
+
const matches = content.match(/v2\.\d+\.\d+/g);
|
|
108
|
+
|
|
109
|
+
if (matches) {
|
|
110
|
+
const nonCurrentVersions = matches.filter(v => {
|
|
111
|
+
const version = v.replace('v', '');
|
|
112
|
+
return version !== newVersion && !isSchemaVersion(version);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
if (nonCurrentVersions.length > 0) {
|
|
116
|
+
strayVersions.push({
|
|
117
|
+
file,
|
|
118
|
+
versions: [...new Set(nonCurrentVersions)]
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
if (strayVersions.length > 0) {
|
|
125
|
+
console.log('\nā ļø Found stray version references (review these manually):');
|
|
126
|
+
strayVersions.forEach(item => {
|
|
127
|
+
console.log(` ${item.file}: ${item.versions.join(', ')}`);
|
|
128
|
+
});
|
|
129
|
+
} else {
|
|
130
|
+
console.log('ā
No stray version references found!');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
console.log(`\nš Version update complete! Now at v${newVersion}`);
|
|
134
|
+
console.log('š Remember to:');
|
|
135
|
+
console.log(' 1. Run: npm run build');
|
|
136
|
+
console.log(' 2. Test: npm test');
|
|
137
|
+
console.log(' 3. Commit with message: "chore: bump version to v' + newVersion + '"');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function isSchemaVersion(version) {
|
|
141
|
+
// These are schema versions that shouldn't change automatically
|
|
142
|
+
const schemaVersions = ['2.4.0', '2.5.0'];
|
|
143
|
+
return schemaVersions.includes(version);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Get version from command line
|
|
147
|
+
const newVersion = process.argv[2];
|
|
148
|
+
updateVersion(newVersion);
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* šļø Build Verification Script
|
|
4
|
+
* Prevents stale builds from reaching npm
|
|
5
|
+
*
|
|
6
|
+
* Checks:
|
|
7
|
+
* 1. All source commands exist in dist/
|
|
8
|
+
* 2. Dist is newer than source
|
|
9
|
+
* 3. All command imports resolve
|
|
10
|
+
* 4. Native parser has all registered commands
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
|
|
16
|
+
// Colors for output
|
|
17
|
+
const colors = {
|
|
18
|
+
reset: '\x1b[0m',
|
|
19
|
+
red: '\x1b[31m',
|
|
20
|
+
green: '\x1b[32m',
|
|
21
|
+
yellow: '\x1b[33m',
|
|
22
|
+
cyan: '\x1b[36m',
|
|
23
|
+
orange: '\x1b[38;5;208m'
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function log(message, color = 'reset') {
|
|
27
|
+
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function error(message) {
|
|
31
|
+
log(`ā ${message}`, 'red');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function success(message) {
|
|
35
|
+
log(`ā
${message}`, 'green');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function warning(message) {
|
|
39
|
+
log(`ā ļø ${message}`, 'yellow');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function info(message) {
|
|
43
|
+
log(`ā¹ļø ${message}`, 'cyan');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Get root directory
|
|
47
|
+
const rootDir = path.join(__dirname, '..');
|
|
48
|
+
const srcDir = path.join(rootDir, 'src');
|
|
49
|
+
const distDir = path.join(rootDir, 'dist');
|
|
50
|
+
|
|
51
|
+
let hasErrors = false;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Check 1: Verify dist directory exists and is built
|
|
55
|
+
*/
|
|
56
|
+
function checkDistExists() {
|
|
57
|
+
info('Check 1: Verifying dist/ directory exists...');
|
|
58
|
+
|
|
59
|
+
if (!fs.existsSync(distDir)) {
|
|
60
|
+
error('dist/ directory does not exist!');
|
|
61
|
+
error('Run: npm run build');
|
|
62
|
+
hasErrors = true;
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!fs.existsSync(path.join(distDir, 'cli.js'))) {
|
|
67
|
+
error('dist/cli.js does not exist!');
|
|
68
|
+
error('Run: npm run build');
|
|
69
|
+
hasErrors = true;
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
success('dist/ directory exists');
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Check 2: Extract all command names from cli.ts
|
|
79
|
+
*/
|
|
80
|
+
function extractCommandsFromSource() {
|
|
81
|
+
info('Check 2: Extracting registered commands from src/cli.ts...');
|
|
82
|
+
|
|
83
|
+
const cliPath = path.join(srcDir, 'cli.ts');
|
|
84
|
+
if (!fs.existsSync(cliPath)) {
|
|
85
|
+
error('src/cli.ts not found!');
|
|
86
|
+
hasErrors = true;
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const content = fs.readFileSync(cliPath, 'utf8');
|
|
91
|
+
|
|
92
|
+
// Extract command registrations: program.command('name')
|
|
93
|
+
const commandRegex = /program\s*\.command\('([^']+)(?:\s+\[)?/g;
|
|
94
|
+
const commands = [];
|
|
95
|
+
let match;
|
|
96
|
+
|
|
97
|
+
while ((match = commandRegex.exec(content)) !== null) {
|
|
98
|
+
const commandName = match[1];
|
|
99
|
+
commands.push(commandName);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Also check for .command() with template strings (rare but possible)
|
|
103
|
+
const templateCommandRegex = /program\s*\.command\(`([^`]+)(?:\s+\[)?/g;
|
|
104
|
+
while ((match = templateCommandRegex.exec(content)) !== null) {
|
|
105
|
+
const commandName = match[1];
|
|
106
|
+
commands.push(commandName);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Remove duplicates and sort
|
|
110
|
+
const uniqueCommands = [...new Set(commands)].sort();
|
|
111
|
+
|
|
112
|
+
success(`Found ${uniqueCommands.length} registered commands`);
|
|
113
|
+
uniqueCommands.forEach(cmd => {
|
|
114
|
+
console.log(` ⢠${cmd}`);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return uniqueCommands;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Check 3: Verify all commands exist in dist/commands/
|
|
122
|
+
*/
|
|
123
|
+
function verifyCommandsInDist(commands) {
|
|
124
|
+
info('Check 3: Verifying commands exist in dist/commands/...');
|
|
125
|
+
|
|
126
|
+
const distCommandsDir = path.join(distDir, 'commands');
|
|
127
|
+
|
|
128
|
+
if (!fs.existsSync(distCommandsDir)) {
|
|
129
|
+
error('dist/commands/ directory does not exist!');
|
|
130
|
+
hasErrors = true;
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
let allExist = true;
|
|
135
|
+
|
|
136
|
+
for (const cmd of commands) {
|
|
137
|
+
// Skip wildcard and special commands
|
|
138
|
+
if (cmd === '*' || cmd.includes('$')) continue;
|
|
139
|
+
|
|
140
|
+
const jsPath = path.join(distCommandsDir, `${cmd}.js`);
|
|
141
|
+
const tsPath = path.join(srcDir, 'commands', `${cmd}.ts`);
|
|
142
|
+
|
|
143
|
+
// Check if source exists first
|
|
144
|
+
if (!fs.existsSync(tsPath)) {
|
|
145
|
+
warning(`Source not found: src/commands/${cmd}.ts (inline command?)`);
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Check if built version exists
|
|
150
|
+
if (!fs.existsSync(jsPath)) {
|
|
151
|
+
error(`Built command missing: dist/commands/${cmd}.js`);
|
|
152
|
+
error(`Source exists at: src/commands/${cmd}.ts`);
|
|
153
|
+
hasErrors = true;
|
|
154
|
+
allExist = false;
|
|
155
|
+
} else {
|
|
156
|
+
success(`${cmd}.js exists in dist/commands/`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return allExist;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Check 4: Verify dist is newer than source
|
|
165
|
+
*/
|
|
166
|
+
function checkDistFreshness() {
|
|
167
|
+
info('Check 4: Verifying dist/ is up-to-date...');
|
|
168
|
+
|
|
169
|
+
const cliSrc = path.join(srcDir, 'cli.ts');
|
|
170
|
+
const cliDist = path.join(distDir, 'cli.js');
|
|
171
|
+
|
|
172
|
+
if (!fs.existsSync(cliDist)) {
|
|
173
|
+
error('dist/cli.js does not exist!');
|
|
174
|
+
hasErrors = true;
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const srcStat = fs.statSync(cliSrc);
|
|
179
|
+
const distStat = fs.statSync(cliDist);
|
|
180
|
+
|
|
181
|
+
if (srcStat.mtime > distStat.mtime) {
|
|
182
|
+
error('src/cli.ts is newer than dist/cli.js!');
|
|
183
|
+
error('Source modified: ' + srcStat.mtime.toISOString());
|
|
184
|
+
error('Build created: ' + distStat.mtime.toISOString());
|
|
185
|
+
error('Run: npm run build');
|
|
186
|
+
hasErrors = true;
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
success('dist/cli.js is up-to-date');
|
|
191
|
+
|
|
192
|
+
// Also check commands directory
|
|
193
|
+
const srcCommandsDir = path.join(srcDir, 'commands');
|
|
194
|
+
const distCommandsDir = path.join(distDir, 'commands');
|
|
195
|
+
|
|
196
|
+
if (!fs.existsSync(srcCommandsDir)) {
|
|
197
|
+
warning('src/commands/ directory not found');
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const srcFiles = fs.readdirSync(srcCommandsDir)
|
|
202
|
+
.filter(f => f.endsWith('.ts'));
|
|
203
|
+
|
|
204
|
+
let staleFound = false;
|
|
205
|
+
|
|
206
|
+
for (const file of srcFiles) {
|
|
207
|
+
const srcPath = path.join(srcCommandsDir, file);
|
|
208
|
+
const distPath = path.join(distCommandsDir, file.replace('.ts', '.js'));
|
|
209
|
+
|
|
210
|
+
if (!fs.existsSync(distPath)) {
|
|
211
|
+
warning(`${file} not built yet`);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const srcStat = fs.statSync(srcPath);
|
|
216
|
+
const distStat = fs.statSync(distPath);
|
|
217
|
+
|
|
218
|
+
if (srcStat.mtime > distStat.mtime) {
|
|
219
|
+
error(`src/commands/${file} is newer than built version!`);
|
|
220
|
+
staleFound = true;
|
|
221
|
+
hasErrors = true;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (staleFound) {
|
|
226
|
+
error('Stale build detected! Run: npm run build');
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
success('All dist/commands/ files are up-to-date');
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Check 5: Verify package.json version matches published
|
|
236
|
+
*/
|
|
237
|
+
function checkVersionSync() {
|
|
238
|
+
info('Check 5: Checking version synchronization...');
|
|
239
|
+
|
|
240
|
+
const packagePath = path.join(rootDir, 'package.json');
|
|
241
|
+
const packageData = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
|
242
|
+
|
|
243
|
+
const currentVersion = packageData.version;
|
|
244
|
+
success(`Current package.json version: ${currentVersion}`);
|
|
245
|
+
|
|
246
|
+
// Note: We can't check npm registry without network call
|
|
247
|
+
// Just warn the user to verify
|
|
248
|
+
warning('Remember to verify this matches your last published version');
|
|
249
|
+
warning('Check with: npm view faf-cli version');
|
|
250
|
+
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Check 6: Verify critical imports exist
|
|
256
|
+
*/
|
|
257
|
+
function checkCriticalImports() {
|
|
258
|
+
info('Check 6: Verifying critical imports...');
|
|
259
|
+
|
|
260
|
+
const criticalPaths = [
|
|
261
|
+
'dist/commands/index.js',
|
|
262
|
+
'dist/commands/init.js',
|
|
263
|
+
'dist/commands/score.js',
|
|
264
|
+
'dist/commands/status.js',
|
|
265
|
+
'dist/utils/native-cli-parser.js',
|
|
266
|
+
'dist/fix-once/commander.js',
|
|
267
|
+
'dist/fix-once/colors.js'
|
|
268
|
+
];
|
|
269
|
+
|
|
270
|
+
let allExist = true;
|
|
271
|
+
|
|
272
|
+
for (const relativePath of criticalPaths) {
|
|
273
|
+
const fullPath = path.join(rootDir, relativePath);
|
|
274
|
+
if (!fs.existsSync(fullPath)) {
|
|
275
|
+
error(`Critical file missing: ${relativePath}`);
|
|
276
|
+
hasErrors = true;
|
|
277
|
+
allExist = false;
|
|
278
|
+
} else {
|
|
279
|
+
success(`${relativePath} ā`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return allExist;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Main verification
|
|
288
|
+
*/
|
|
289
|
+
function main() {
|
|
290
|
+
log('\nšļø FAF Build Verification - Championship Grade', 'cyan');
|
|
291
|
+
log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n', 'cyan');
|
|
292
|
+
|
|
293
|
+
// Run all checks
|
|
294
|
+
const distExists = checkDistExists();
|
|
295
|
+
console.log();
|
|
296
|
+
|
|
297
|
+
if (!distExists) {
|
|
298
|
+
log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā', 'red');
|
|
299
|
+
error('Build verification FAILED!');
|
|
300
|
+
error('Fix the errors above and try again');
|
|
301
|
+
log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n', 'red');
|
|
302
|
+
process.exit(1);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const commands = extractCommandsFromSource();
|
|
306
|
+
console.log();
|
|
307
|
+
|
|
308
|
+
verifyCommandsInDist(commands);
|
|
309
|
+
console.log();
|
|
310
|
+
|
|
311
|
+
checkDistFreshness();
|
|
312
|
+
console.log();
|
|
313
|
+
|
|
314
|
+
checkCriticalImports();
|
|
315
|
+
console.log();
|
|
316
|
+
|
|
317
|
+
checkVersionSync();
|
|
318
|
+
console.log();
|
|
319
|
+
|
|
320
|
+
// Final result
|
|
321
|
+
if (hasErrors) {
|
|
322
|
+
log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā', 'red');
|
|
323
|
+
error('Build verification FAILED! ā');
|
|
324
|
+
error('Fix the errors above before publishing');
|
|
325
|
+
log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n', 'red');
|
|
326
|
+
process.exit(1);
|
|
327
|
+
} else {
|
|
328
|
+
log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā', 'green');
|
|
329
|
+
success('Build verification PASSED! ā
');
|
|
330
|
+
success('Safe to publish to npm');
|
|
331
|
+
log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n', 'green');
|
|
332
|
+
|
|
333
|
+
// Helpful next steps
|
|
334
|
+
info('Next steps:');
|
|
335
|
+
console.log(' 1. npm version patch # Bump to 2.4.15');
|
|
336
|
+
console.log(' 2. npm publish # Push to npm');
|
|
337
|
+
console.log(' 3. npm install -g faf-cli@latest # Update global');
|
|
338
|
+
console.log(' 4. faf index # Test it works!\n');
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Run verification
|
|
343
|
+
main();
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* šÆ VERSION SANITY CHECKER
|
|
4
|
+
* Never get surprised by version conflicts again!
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { execSync } = require('child_process');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
console.log('š VERSION CHECK - No more surprises!\n');
|
|
12
|
+
|
|
13
|
+
// 1. Get local version
|
|
14
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'), 'utf8'));
|
|
15
|
+
const localVersion = packageJson.version;
|
|
16
|
+
|
|
17
|
+
// 2. Get npm registry version
|
|
18
|
+
let npmVersion;
|
|
19
|
+
try {
|
|
20
|
+
npmVersion = execSync('npm view faf-cli version', { encoding: 'utf8' }).trim();
|
|
21
|
+
} catch (e) {
|
|
22
|
+
console.log('ā ļø Package not found on npm (first publish?)');
|
|
23
|
+
npmVersion = '0.0.0';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 3. Get all published versions
|
|
27
|
+
let allVersions;
|
|
28
|
+
try {
|
|
29
|
+
allVersions = JSON.parse(execSync('npm view faf-cli versions --json', { encoding: 'utf8' }));
|
|
30
|
+
} catch (e) {
|
|
31
|
+
allVersions = [];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 4. THE TRUTH
|
|
35
|
+
console.log('š VERSION REALITY CHECK:');
|
|
36
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
37
|
+
console.log(`š LOCAL (package.json): v${localVersion}`);
|
|
38
|
+
console.log(`āļø NPM LATEST: v${npmVersion}`);
|
|
39
|
+
console.log(`š LAST 5 PUBLISHED: ${allVersions.slice(-5).join(', ')}`);
|
|
40
|
+
console.log('');
|
|
41
|
+
|
|
42
|
+
// 5. CONFLICT DETECTION
|
|
43
|
+
let hasConflict = false;
|
|
44
|
+
if (localVersion === npmVersion) {
|
|
45
|
+
console.log('ā CONFLICT: Local version matches npm!');
|
|
46
|
+
console.log(' You need to bump version before publishing:');
|
|
47
|
+
console.log(' ā npm version patch');
|
|
48
|
+
console.log('');
|
|
49
|
+
hasConflict = true;
|
|
50
|
+
} else if (allVersions.includes(localVersion)) {
|
|
51
|
+
console.log('ā CONFLICT: Version already exists on npm!');
|
|
52
|
+
console.log(` v${localVersion} was already published`);
|
|
53
|
+
console.log(' ā npm version patch');
|
|
54
|
+
console.log('');
|
|
55
|
+
hasConflict = true;
|
|
56
|
+
} else {
|
|
57
|
+
console.log('ā
CLEAR: Ready to publish!');
|
|
58
|
+
console.log(` Will publish as v${localVersion}`);
|
|
59
|
+
console.log('');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 6. SUGGESTED NEXT VERSION
|
|
63
|
+
const parts = npmVersion.split('.');
|
|
64
|
+
const suggestedPatch = `${parts[0]}.${parts[1]}.${parseInt(parts[2]) + 1}`;
|
|
65
|
+
const suggestedMinor = `${parts[0]}.${parseInt(parts[1]) + 1}.0`;
|
|
66
|
+
const suggestedMajor = `${parseInt(parts[0]) + 1}.0.0`;
|
|
67
|
+
|
|
68
|
+
console.log('š SUGGESTED VERSIONS:');
|
|
69
|
+
console.log(` Patch: v${suggestedPatch} (bug fixes)`)
|
|
70
|
+
console.log(` Minor: v${suggestedMinor} (new features)`);
|
|
71
|
+
console.log(` Major: v${suggestedMajor} (breaking changes)`);
|
|
72
|
+
console.log('');
|
|
73
|
+
console.log('š” Run: npm version patch|minor|major');
|
|
74
|
+
|
|
75
|
+
// Exit with error if conflict
|
|
76
|
+
if (hasConflict) {
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|