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.
Files changed (53) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +40 -22
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/readme.d.ts +11 -6
  5. package/dist/commands/readme.d.ts.map +1 -1
  6. package/dist/commands/readme.js +167 -120
  7. package/dist/commands/readme.js.map +1 -1
  8. package/dist/commands/show.d.ts.map +1 -1
  9. package/dist/commands/show.js +22 -7
  10. package/dist/commands/show.js.map +1 -1
  11. package/dist/commands/sixws.d.ts +6 -0
  12. package/dist/commands/sixws.d.ts.map +1 -0
  13. package/dist/commands/sixws.js +154 -0
  14. package/dist/commands/sixws.js.map +1 -0
  15. package/dist/utils/file-utils.d.ts.map +1 -1
  16. package/dist/utils/file-utils.js +1 -4
  17. package/dist/utils/file-utils.js.map +1 -1
  18. package/package.json +5 -2
  19. package/project.faf +4 -4
  20. package/scripts/ANTHROPIC-DEMO.sh +203 -0
  21. package/scripts/boris-ready.sh +169 -0
  22. package/scripts/bundle-yaml.js +87 -0
  23. package/scripts/check-version.js +88 -0
  24. package/scripts/clean-build.js +34 -0
  25. package/scripts/cleanup-unused.sh +54 -0
  26. package/scripts/debug-django.txt +9 -0
  27. package/scripts/debug-mongo.txt +9 -0
  28. package/scripts/debug-react.txt +9 -0
  29. package/scripts/debug-rust.txt +9 -0
  30. package/scripts/debug-whisper.cpp.txt +9 -0
  31. package/scripts/evaluate-family-member.ts +300 -0
  32. package/scripts/generate-docs.ts +358 -0
  33. package/scripts/generate-drift-reports.sh +111 -0
  34. package/scripts/industry-showcase.json +122 -0
  35. package/scripts/mcp-ecosystem-research.sh +58 -0
  36. package/scripts/migrate-yaml-imports.sh +55 -0
  37. package/scripts/migrate-yaml.ts +132 -0
  38. package/scripts/performance-validation.ts +460 -0
  39. package/scripts/postinstall.js +30 -0
  40. package/scripts/prepare-release.ts +421 -0
  41. package/scripts/run-industry-showcase.ts +237 -0
  42. package/scripts/run-test-showcase.ts +244 -0
  43. package/scripts/setup-github-watch.sh +43 -0
  44. package/scripts/sync-version.js +35 -0
  45. package/scripts/test-integration-detection.ts +93 -0
  46. package/scripts/test-integration-simple.js +93 -0
  47. package/scripts/test-medal-progression.sh +143 -0
  48. package/scripts/test-showcase-results.json +109 -0
  49. package/scripts/test-showcase.json +32 -0
  50. package/scripts/update-version.js +148 -0
  51. package/scripts/verify-build.js +343 -0
  52. package/scripts/version-check.js +78 -0
  53. package/scripts/watch-discussions.sh +86 -0
@@ -0,0 +1,244 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Test Showcase Runner (5 repos)
4
+ * Tests the showcase runner on a small sample before running full 70 repos
5
+ */
6
+
7
+ import { execSync } from 'child_process';
8
+ import { readFileSync, writeFileSync } from 'fs';
9
+ import { join } from 'path';
10
+ import * as yaml from 'yaml';
11
+
12
+ interface ShowcaseData {
13
+ title: string;
14
+ description: string;
15
+ updated: string;
16
+ categories: Array<{
17
+ name: string;
18
+ repos: string[];
19
+ }>;
20
+ }
21
+
22
+ interface RepoResult {
23
+ repo: string;
24
+ owner: string;
25
+ name: string;
26
+ category: string;
27
+ currentScore: number;
28
+ newScore: number;
29
+ improvement: number;
30
+ tier: string;
31
+ stack: {
32
+ frontend?: string;
33
+ backend?: string;
34
+ runtime?: string;
35
+ build?: string;
36
+ database?: string;
37
+ hosting?: string;
38
+ };
39
+ projectType: string;
40
+ mainLanguage: string;
41
+ description: string;
42
+ status: 'success' | 'failed' | 'rate-limited';
43
+ error?: string;
44
+ }
45
+
46
+ interface ShowcaseResults {
47
+ generated: string;
48
+ totalRepos: number;
49
+ successCount: number;
50
+ failedCount: number;
51
+ avgImprovement: number;
52
+ categories: Array<{
53
+ name: string;
54
+ repos: RepoResult[];
55
+ }>;
56
+ }
57
+
58
+ function parseFafGitOutput(output: string): { currentScore: number; newScore: number; improvement: number; tier: string } | null {
59
+ // Strip ANSI color codes first
60
+ // eslint-disable-next-line no-control-regex
61
+ const cleanOutput = output.replace(/\x1b\[[0-9;]*m/g, '');
62
+
63
+ // v4.3.0 format (after stripping colors):
64
+ // Current: No .faf file โš ๏ธ
65
+ // With FAF: 100% ๐Ÿ† Trophy
66
+
67
+ const currentMatch = cleanOutput.match(/Current:\s+No \.faf file/);
68
+ const withFafMatch = cleanOutput.match(/With FAF:\s+(\d+)%\s+([๐Ÿ†๐Ÿฅ‡๐Ÿฅˆ๐Ÿฅ‰๐ŸŸข๐ŸŸก๐Ÿ”ด๐Ÿคโš ๏ธ]+)\s*(\w+)?/);
69
+
70
+ if (!withFafMatch) {
71
+ return null;
72
+ }
73
+
74
+ const currentScore = currentMatch ? 0 : 0; // Always 0 for "No .faf file"
75
+ const newScore = parseInt(withFafMatch[1]);
76
+ const tier = withFafMatch[3] || 'Unknown';
77
+ const improvement = newScore - currentScore;
78
+
79
+ return {
80
+ currentScore,
81
+ newScore,
82
+ improvement,
83
+ tier
84
+ };
85
+ }
86
+
87
+ function extractStackFromFaf(fafPath: string): any {
88
+ try {
89
+ const content = readFileSync(fafPath, 'utf-8');
90
+ const parsed = yaml.parse(content);
91
+
92
+ return {
93
+ stack: {
94
+ frontend: parsed.stack?.frontend !== 'slotignored' ? parsed.stack?.frontend : undefined,
95
+ backend: parsed.stack?.backend !== 'slotignored' ? parsed.stack?.backend : undefined,
96
+ runtime: parsed.stack?.runtime !== 'slotignored' ? parsed.stack?.runtime : undefined,
97
+ build: parsed.stack?.build !== 'slotignored' ? parsed.stack?.build : undefined,
98
+ database: parsed.stack?.database !== 'slotignored' ? parsed.stack?.database : undefined,
99
+ hosting: parsed.stack?.hosting !== 'slotignored' ? parsed.stack?.hosting : undefined,
100
+ },
101
+ projectType: parsed.project?.type || 'unknown',
102
+ mainLanguage: parsed.project?.main_language || 'unknown',
103
+ description: parsed.project?.goal || parsed.metadata?.description || ''
104
+ };
105
+ } catch (e) {
106
+ return {
107
+ stack: {},
108
+ projectType: 'unknown',
109
+ mainLanguage: 'unknown',
110
+ description: ''
111
+ };
112
+ }
113
+ }
114
+
115
+ async function runTestShowcase() {
116
+ console.log('๐ŸŽ๏ธ FAF Test Showcase Runner (5 repos)\n');
117
+
118
+ // Read test showcase data
119
+ const showcaseData: ShowcaseData = JSON.parse(
120
+ readFileSync(join(__dirname, 'test-showcase.json'), 'utf-8')
121
+ );
122
+
123
+ const results: ShowcaseResults = {
124
+ generated: new Date().toISOString(),
125
+ totalRepos: 0,
126
+ successCount: 0,
127
+ failedCount: 0,
128
+ avgImprovement: 0,
129
+ categories: []
130
+ };
131
+
132
+ let totalImprovement = 0;
133
+
134
+ for (const category of showcaseData.categories) {
135
+ console.log(`\n๐Ÿ“ Category: ${category.name}`);
136
+ console.log(` Testing ${category.repos.length} repos...\n`);
137
+
138
+ const categoryResults: RepoResult[] = [];
139
+
140
+ for (const repo of category.repos) {
141
+ results.totalRepos++;
142
+ const [owner, name] = repo.split('/');
143
+
144
+ process.stdout.write(` โšก ${repo}... `);
145
+
146
+ try {
147
+ // Run faf git (use local build to avoid bin name collision with bun-sticky)
148
+ const output = execSync(
149
+ `node ${join(__dirname, '../dist/cli.js')} git ${repo}`,
150
+ {
151
+ encoding: 'utf-8',
152
+ timeout: 30000,
153
+ stdio: 'pipe'
154
+ }
155
+ );
156
+
157
+ // Parse output
158
+ const scores = parseFafGitOutput(output);
159
+
160
+ if (!scores) {
161
+ // Debug: save output to file
162
+ const debugPath = join(__dirname, `debug-${name}.txt`);
163
+ writeFileSync(debugPath, output);
164
+ throw new Error(`Failed to parse output (saved to ${debugPath})`);
165
+ }
166
+
167
+ // Extract stack from generated .faf file
168
+ const fafPath = join(process.cwd(), `${name}.faf`);
169
+ const fafData = extractStackFromFaf(fafPath);
170
+
171
+ const result: RepoResult = {
172
+ repo,
173
+ owner,
174
+ name,
175
+ category: category.name,
176
+ currentScore: scores.currentScore,
177
+ newScore: scores.newScore,
178
+ improvement: scores.improvement,
179
+ tier: scores.tier,
180
+ stack: fafData.stack,
181
+ projectType: fafData.projectType,
182
+ mainLanguage: fafData.mainLanguage,
183
+ description: fafData.description,
184
+ status: 'success'
185
+ };
186
+
187
+ categoryResults.push(result);
188
+ results.successCount++;
189
+ totalImprovement += scores.improvement;
190
+
191
+ console.log(`โœ… ${scores.currentScore}% โ†’ ${scores.newScore}% (+${scores.improvement})`);
192
+
193
+ } catch (error: any) {
194
+ results.failedCount++;
195
+
196
+ const result: RepoResult = {
197
+ repo,
198
+ owner,
199
+ name,
200
+ category: category.name,
201
+ currentScore: 0,
202
+ newScore: 0,
203
+ improvement: 0,
204
+ tier: 'Failed',
205
+ stack: {},
206
+ projectType: 'unknown',
207
+ mainLanguage: 'unknown',
208
+ description: '',
209
+ status: error.message?.includes('rate limit') ? 'rate-limited' : 'failed',
210
+ error: error.message
211
+ };
212
+
213
+ categoryResults.push(result);
214
+ console.log(`โŒ ${error.message.split('\n')[0]}`);
215
+ }
216
+
217
+ // Rate limit protection (1 second between requests)
218
+ await new Promise(resolve => setTimeout(resolve, 1000));
219
+ }
220
+
221
+ results.categories.push({
222
+ name: category.name,
223
+ repos: categoryResults
224
+ });
225
+ }
226
+
227
+ // Calculate average improvement
228
+ results.avgImprovement = results.successCount > 0
229
+ ? Math.round(totalImprovement / results.successCount)
230
+ : 0;
231
+
232
+ // Save results
233
+ const outputPath = join(__dirname, 'test-showcase-results.json');
234
+ writeFileSync(outputPath, JSON.stringify(results, null, 2));
235
+
236
+ console.log(`\n\n๐Ÿ† Test Showcase Complete!\n`);
237
+ console.log(` Total Repos: ${results.totalRepos}`);
238
+ console.log(` โœ… Success: ${results.successCount}`);
239
+ console.log(` โŒ Failed: ${results.failedCount}`);
240
+ console.log(` ๐Ÿ“ˆ Avg Improvement: +${results.avgImprovement} points\n`);
241
+ console.log(`๐Ÿ“„ Results saved to: ${outputPath}\n`);
242
+ }
243
+
244
+ runTestShowcase().catch(console.error);
@@ -0,0 +1,43 @@
1
+ #!/bin/bash
2
+ # ๐Ÿฉต Setup GitHub Discussions Watching for FAF
3
+
4
+ echo "๐Ÿฉต Setting up GitHub Discussions alerts for FAF..."
5
+ echo ""
6
+
7
+ # Check if gh is installed
8
+ if ! command -v gh &> /dev/null; then
9
+ echo "โŒ GitHub CLI (gh) is not installed"
10
+ echo "Install with: brew install gh"
11
+ exit 1
12
+ fi
13
+
14
+ # Check authentication
15
+ if ! gh auth status &> /dev/null; then
16
+ echo "โŒ Not authenticated with GitHub"
17
+ echo "Run: gh auth login"
18
+ exit 1
19
+ fi
20
+
21
+ echo "โœ… GitHub CLI authenticated"
22
+
23
+ # Watch the repository
24
+ echo "๐Ÿ“บ Watching FAF repository for activity..."
25
+ gh api -X PUT repos/Wolfe-Jam/faf/subscription \
26
+ --field subscribed=true \
27
+ --field ignored=false 2>/dev/null && echo "โœ… Subscribed to repository notifications"
28
+
29
+ # Enable web notifications for discussions
30
+ echo "๐Ÿ”” Enabling discussion notifications..."
31
+ gh api -X PUT repos/Wolfe-Jam/faf/notifications \
32
+ --field discussions=true 2>/dev/null || echo "โ„น๏ธ Notifications API not available (normal)"
33
+
34
+ echo ""
35
+ echo "๐Ÿฉต Setup complete! You can now:"
36
+ echo " 1. Run ./scripts/watch-discussions.sh to monitor in terminal"
37
+ echo " 2. Check https://github.com/Wolfe-Jam/faf/discussions for activity"
38
+ echo " 3. View notifications at https://github.com/notifications"
39
+ echo ""
40
+ echo "๐Ÿ’ก For best results, also enable notifications in GitHub web settings:"
41
+ echo " https://github.com/settings/notifications"
42
+ echo ""
43
+ echo "Thank you for engaging with the FAF community! ๐Ÿฉตโšก"
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Sync version from package.json to project.faf
4
+ * Run: npm run sync-version
5
+ * Auto-runs on: npm version (via "version" lifecycle hook)
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+
11
+ const packageJsonPath = path.join(__dirname, '..', 'package.json');
12
+ const projectFafPath = path.join(__dirname, '..', 'project.faf');
13
+
14
+ try {
15
+ // Read version from package.json
16
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
17
+ const version = packageJson.version;
18
+
19
+ // Read project.faf
20
+ let projectFaf = fs.readFileSync(projectFafPath, 'utf-8');
21
+
22
+ // Update version field
23
+ projectFaf = projectFaf.replace(
24
+ /^(\s*version:\s*).+$/m,
25
+ `$1${version}`
26
+ );
27
+
28
+ // Write back
29
+ fs.writeFileSync(projectFafPath, projectFaf);
30
+
31
+ console.log(`Synced project.faf version to ${version}`);
32
+ } catch (error) {
33
+ console.error('Failed to sync version:', error.message);
34
+ process.exit(1);
35
+ }
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env ts-node
2
+ /**
3
+ * Test Integration Detection System
4
+ *
5
+ * Tests FAF Family detectors on real projects
6
+ */
7
+
8
+ import { integrationRegistry } from '../src/family/registry';
9
+ import { resolve } from 'path';
10
+
11
+ async function testProject(projectPath: string, projectName: string) {
12
+ console.log(`\n${'='.repeat(60)}`);
13
+ console.log(`๐Ÿ” Testing: ${projectName}`);
14
+ console.log(`๐Ÿ“ Path: ${projectPath}`);
15
+ console.log(`${'='.repeat(60)}\n`);
16
+
17
+ try {
18
+ // Detect all integrations
19
+ const detected = await integrationRegistry.detectAll(projectPath);
20
+
21
+ if (detected.length === 0) {
22
+ console.log('โŒ No integrations detected\n');
23
+ return;
24
+ }
25
+
26
+ console.log(`โœ… Detected ${detected.length} integration(s):\n`);
27
+
28
+ // Show each detected integration
29
+ detected.forEach((integration, index) => {
30
+ const emoji = {
31
+ trophy: '๐Ÿ†',
32
+ gold: '๐Ÿฅ‡',
33
+ silver: '๐Ÿฅˆ',
34
+ bronze: '๐Ÿฅ‰',
35
+ }[integration.tier] || 'โšช';
36
+
37
+ console.log(`${index + 1}. ${emoji} ${integration.displayName}`);
38
+ console.log(` Tier: ${integration.tier} (${integration.qualityScore} quality score)`);
39
+ console.log(` Weekly adoption: ${integration.weeklyAdoption.toLocaleString()} developers`);
40
+ console.log(` MCP servers: ${integration.mcpServers.join(', ')}`);
41
+ console.log(` Context slots: ${integration.contextContribution.join(', ')}`);
42
+ console.log('');
43
+ });
44
+
45
+ // Generate combined context
46
+ console.log('๐Ÿ“Š Generating combined .faf context...\n');
47
+ const context = await integrationRegistry.generateContext(projectPath);
48
+
49
+ console.log('Generated Context:');
50
+ console.log(JSON.stringify(context, null, 2));
51
+ console.log('');
52
+
53
+ } catch (error) {
54
+ console.error('โŒ Error testing project:', error);
55
+ }
56
+ }
57
+
58
+ async function main() {
59
+ console.log('๐Ÿ† FAF Integration Detection System - Test Suite\n');
60
+ console.log('Championship Standard: Auto-detect stacks and generate optimized .faf context\n');
61
+
62
+ const testProjects = [
63
+ {
64
+ name: 'faf-cli (this project)',
65
+ path: resolve(__dirname, '..'),
66
+ },
67
+ {
68
+ name: 'claude-faf-mcp',
69
+ path: resolve(__dirname, '../../claude-faf-mcp'),
70
+ },
71
+ ];
72
+
73
+ for (const project of testProjects) {
74
+ await testProject(project.path, project.name);
75
+ }
76
+
77
+ // Show registry stats
78
+ console.log(`\n${'='.repeat(60)}`);
79
+ console.log('๐Ÿ“ˆ Integration Registry Statistics');
80
+ console.log(`${'='.repeat(60)}\n`);
81
+
82
+ const stats = integrationRegistry.getStats();
83
+ console.log(`Total integrations: ${stats.total}`);
84
+ console.log(`Total weekly adoption: ${stats.totalWeeklyAdoption.toLocaleString()} developers`);
85
+ console.log('\nBy tier:');
86
+ Object.entries(stats.byTier).forEach(([tier, count]) => {
87
+ console.log(` ${tier}: ${count}`);
88
+ });
89
+
90
+ console.log('\n๐Ÿ Test suite complete!');
91
+ }
92
+
93
+ main().catch(console.error);
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Test Integration Detection System (Simple JavaScript version)
4
+ *
5
+ * Tests FAF Family detectors on real projects
6
+ */
7
+
8
+ const { integrationRegistry } = require('../dist/family/registry.js');
9
+ const { resolve } = require('path');
10
+
11
+ async function testProject(projectPath, projectName) {
12
+ console.log(`\n${'='.repeat(60)}`);
13
+ console.log(`๐Ÿ” Testing: ${projectName}`);
14
+ console.log(`๐Ÿ“ Path: ${projectPath}`);
15
+ console.log(`${'='.repeat(60)}\n`);
16
+
17
+ try {
18
+ // Detect all integrations
19
+ const detected = await integrationRegistry.detectAll(projectPath);
20
+
21
+ if (detected.length === 0) {
22
+ console.log('โŒ No integrations detected\n');
23
+ return;
24
+ }
25
+
26
+ console.log(`โœ… Detected ${detected.length} integration(s):\n`);
27
+
28
+ // Show each detected integration
29
+ detected.forEach((integration, index) => {
30
+ const emoji = {
31
+ trophy: '๐Ÿ†',
32
+ gold: '๐Ÿฅ‡',
33
+ silver: '๐Ÿฅˆ',
34
+ bronze: '๐Ÿฅ‰',
35
+ }[integration.tier] || 'โšช';
36
+
37
+ console.log(`${index + 1}. ${emoji} ${integration.displayName}`);
38
+ console.log(` Tier: ${integration.tier} (${integration.qualityScore} quality score)`);
39
+ console.log(` Weekly adoption: ${integration.weeklyAdoption.toLocaleString()} developers`);
40
+ console.log(` MCP servers: ${integration.mcpServers.join(', ')}`);
41
+ console.log(` Context slots: ${integration.contextContribution.join(', ')}`);
42
+ console.log('');
43
+ });
44
+
45
+ // Generate combined context
46
+ console.log('๐Ÿ“Š Generating combined .faf context...\n');
47
+ const context = await integrationRegistry.generateContext(projectPath);
48
+
49
+ console.log('Generated Context:');
50
+ console.log(JSON.stringify(context, null, 2));
51
+ console.log('');
52
+
53
+ } catch (error) {
54
+ console.error('โŒ Error testing project:', error.message);
55
+ }
56
+ }
57
+
58
+ async function main() {
59
+ console.log('๐Ÿ† FAF Integration Detection System - Test Suite\n');
60
+ console.log('Championship Standard: Auto-detect stacks and generate optimized .faf context\n');
61
+
62
+ const testProjects = [
63
+ {
64
+ name: 'faf-cli (this project)',
65
+ path: resolve(__dirname, '..'),
66
+ },
67
+ {
68
+ name: 'claude-faf-mcp',
69
+ path: resolve(__dirname, '../../claude-faf-mcp'),
70
+ },
71
+ ];
72
+
73
+ for (const project of testProjects) {
74
+ await testProject(project.path, project.name);
75
+ }
76
+
77
+ // Show registry stats
78
+ console.log(`\n${'='.repeat(60)}`);
79
+ console.log('๐Ÿ“ˆ Integration Registry Statistics');
80
+ console.log(`${'='.repeat(60)}\n`);
81
+
82
+ const stats = integrationRegistry.getStats();
83
+ console.log(`Total integrations: ${stats.total}`);
84
+ console.log(`Total weekly adoption: ${stats.totalWeeklyAdoption.toLocaleString()} developers`);
85
+ console.log('\nBy tier:');
86
+ Object.entries(stats.byTier).forEach(([tier, count]) => {
87
+ console.log(` ${tier}: ${count}`);
88
+ });
89
+
90
+ console.log('\n๐Ÿ Test suite complete!');
91
+ }
92
+
93
+ main().catch(console.error);
@@ -0,0 +1,143 @@
1
+ #!/bin/bash
2
+
3
+ ##
4
+ # ๐Ÿ WJTC Medal Progression Visual Test
5
+ # Manual verification of championship medal display
6
+ #
7
+ # Philosophy: "We break things so others never even know they were ever broken"
8
+ ##
9
+
10
+ set -e
11
+
12
+ echo "๐ŸŽ๏ธโšก๏ธ WJTC MEDAL PROGRESSION TEST - Championship Visual Verification"
13
+ echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”"
14
+ echo ""
15
+
16
+ # Test scores covering all medal tiers
17
+ TEST_SCORES=(
18
+ "0:๐Ÿ”ด Stop - Needs work"
19
+ "48:๐Ÿ”ด Stop - Needs work (near threshold)"
20
+ "55:๐ŸŸก Caution - Getting ready"
21
+ "62:๐ŸŸก Caution - Getting ready (mid-range)"
22
+ "70:๐ŸŸข GO! - Ready for Target 1"
23
+ "77:๐ŸŸข GO! - Ready for Target 1 (mid-range)"
24
+ "85:๐Ÿฅ‰ Target 1 - Bronze"
25
+ "88:๐Ÿฅ‰ Target 1 - Bronze (mid-range)"
26
+ "95:๐Ÿฅˆ Target 2 - Silver"
27
+ "96:๐Ÿฅˆ Target 2 - Silver (mid-range)"
28
+ "99:๐Ÿฅ‡ Gold"
29
+ "100:๐Ÿ† Trophy - Championship"
30
+ )
31
+
32
+ # Create temp directory
33
+ TEST_DIR="/tmp/faf-medal-test-$$"
34
+ mkdir -p "$TEST_DIR"
35
+
36
+ echo "๐Ÿ“ Test directory: $TEST_DIR"
37
+ echo ""
38
+
39
+ # Function to create a test .faf file with specific score
40
+ create_test_faf() {
41
+ local score=$1
42
+ local label=$2
43
+ local dir="$TEST_DIR/project-$score"
44
+
45
+ mkdir -p "$dir"
46
+
47
+ # Calculate filled slots based on score
48
+ # 21 total slots, so score% = (filled/21) * 100
49
+ local filled_slots=$(echo "scale=0; ($score * 21) / 100" | bc)
50
+
51
+ # Create minimal .faf file
52
+ cat > "$dir/.faf" <<EOF
53
+ faf_version: "2.4.0"
54
+ ai_scoring_system: "2025-08-30"
55
+ ai_score: "${score}%"
56
+ ai_confidence: $([ $score -ge 70 ] && echo "HIGH" || echo "LOW")
57
+ project:
58
+ name: "Test Project $score%"
59
+ goal: "Testing medal display at $score%"
60
+ main_language: "TypeScript"
61
+ stack:
62
+ frontend: "React"
63
+ backend: "Node.js"
64
+ database: "PostgreSQL"
65
+ human_context:
66
+ who: "Developers"
67
+ what: "Test project for medal validation"
68
+ why: "WJTC championship testing"
69
+ where: "Testing environment"
70
+ when: "Now"
71
+ how: "Manual test script"
72
+ ai_instructions:
73
+ priority_order:
74
+ - "Test medal display"
75
+ working_style:
76
+ code_first: true
77
+ context_quality:
78
+ slots_filled: "$filled_slots/21 (${score}%)"
79
+ ai_confidence: $([ $score -ge 70 ] && echo "HIGH" || echo "LOW")
80
+ EOF
81
+
82
+ echo "$dir"
83
+ }
84
+
85
+ echo "๐Ÿ”จ Creating test projects..."
86
+ echo ""
87
+
88
+ # Create all test projects
89
+ TEST_PROJECTS=()
90
+ for entry in "${TEST_SCORES[@]}"; do
91
+ score="${entry%%:*}"
92
+ label="${entry#*:}"
93
+
94
+ project_dir=$(create_test_faf "$score" "$label")
95
+ TEST_PROJECTS+=("$score:$label:$project_dir")
96
+
97
+ echo " โœ… Created: $score% - $label"
98
+ done
99
+
100
+ echo ""
101
+ echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”"
102
+ echo "๐Ÿ RUNNING VISUAL VERIFICATION TESTS"
103
+ echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”"
104
+ echo ""
105
+
106
+ # Run faf show on each project
107
+ for entry in "${TEST_PROJECTS[@]}"; do
108
+ score="${entry%%:*}"
109
+ rest="${entry#*:}"
110
+ label="${rest%%:*}"
111
+ project_dir="${rest#*:}"
112
+
113
+ echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”"
114
+ echo "๐Ÿ“Š Testing: $score% - $label"
115
+ echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”"
116
+ echo ""
117
+
118
+ # Run faf show
119
+ npx ts-node src/cli.ts show "$project_dir"
120
+
121
+ echo ""
122
+ echo "โœ… Verify: Medal matches expected '$label'"
123
+ echo ""
124
+ read -p "Press Enter to continue to next test..."
125
+ echo ""
126
+ done
127
+
128
+ echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”"
129
+ echo "๐Ÿ† WJTC MEDAL PROGRESSION TEST COMPLETE"
130
+ echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”"
131
+ echo ""
132
+ echo "๐Ÿ“‹ Manual Verification Checklist:"
133
+ echo ""
134
+ echo " [ ] All medals display correctly"
135
+ echo " [ ] Traffic light progression is clear (๐Ÿ”ดโ†’๐ŸŸกโ†’๐ŸŸข)"
136
+ echo " [ ] Medal progression is clear (๐Ÿฅ‰โ†’๐Ÿฅˆโ†’๐Ÿฅ‡โ†’๐Ÿ†)"
137
+ echo " [ ] No medals shown at wrong scores"
138
+ echo " [ ] Colors match medal tier appropriately"
139
+ echo ""
140
+ echo "๐Ÿงน Cleanup: rm -rf $TEST_DIR"
141
+ echo ""
142
+ echo "Status: ${GREEN}READY FOR WJTC REPORT${NC}"
143
+ echo ""