faf-mcp 2.0.1 → 2.1.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 (67) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/CLAUDE.md +23 -21
  3. package/README.md +27 -24
  4. package/dist/src/cli.js +1 -1
  5. package/dist/src/cli.js.map +1 -1
  6. package/dist/src/faf-core/commands/auto.d.ts +2 -2
  7. package/dist/src/faf-core/commands/auto.js.map +1 -1
  8. package/dist/src/faf-core/commands/innit.d.ts +2 -2
  9. package/dist/src/faf-core/commands/innit.js.map +1 -1
  10. package/dist/src/faf-core/commands/score.d.ts +1 -1
  11. package/dist/src/faf-core/commands/score.js.map +1 -1
  12. package/dist/src/faf-core/generators/faf-generator-championship.js.map +1 -1
  13. package/dist/src/faf-core/parsers/agents-parser.d.ts +1 -1
  14. package/dist/src/faf-core/parsers/agents-parser.js +2 -2
  15. package/dist/src/faf-core/parsers/agents-parser.js.map +1 -1
  16. package/dist/src/faf-core/parsers/conductor-parser.d.ts +1 -1
  17. package/dist/src/faf-core/parsers/conductor-parser.js +1 -1
  18. package/dist/src/faf-core/parsers/cursorrules-parser.d.ts +1 -1
  19. package/dist/src/faf-core/parsers/cursorrules-parser.js +2 -2
  20. package/dist/src/faf-core/parsers/cursorrules-parser.js.map +1 -1
  21. package/dist/src/faf-core/parsers/faf-git-generator.d.ts +1 -1
  22. package/dist/src/faf-core/parsers/faf-git-generator.js +2 -2
  23. package/dist/src/faf-core/parsers/faf-git-generator.js.map +1 -1
  24. package/dist/src/faf-core/parsers/gemini-parser.d.ts +1 -1
  25. package/dist/src/faf-core/parsers/gemini-parser.js +1 -1
  26. package/dist/src/faf-core/parsers/github-extractor.d.ts +1 -1
  27. package/dist/src/faf-core/parsers/github-extractor.js +2 -2
  28. package/dist/src/faf-core/parsers/github-extractor.js.map +1 -1
  29. package/dist/src/faf-core/parsers/slot-counter.d.ts +1 -1
  30. package/dist/src/faf-core/parsers/slot-counter.js +1 -1
  31. package/dist/src/handlers/championship-tools.d.ts +6 -13
  32. package/dist/src/handlers/championship-tools.js +122 -530
  33. package/dist/src/handlers/championship-tools.js.map +1 -1
  34. package/dist/src/handlers/engine-adapter.js +3 -3
  35. package/dist/src/handlers/engine-adapter.js.map +1 -1
  36. package/dist/src/handlers/fileHandler.d.ts +1 -1
  37. package/dist/src/handlers/fileHandler.js +1 -1
  38. package/dist/src/handlers/fileHandler.js.map +1 -1
  39. package/dist/src/handlers/resources.d.ts +1 -1
  40. package/dist/src/handlers/tool-registry.d.ts +2 -2
  41. package/dist/src/handlers/tools.d.ts +1 -1
  42. package/dist/src/handlers/tools.js +116 -135
  43. package/dist/src/handlers/tools.js.map +1 -1
  44. package/dist/src/index.js +2 -2
  45. package/dist/src/index.js.map +1 -1
  46. package/dist/src/server.d.ts +8 -3
  47. package/dist/src/server.js +16 -10
  48. package/dist/src/server.js.map +1 -1
  49. package/dist/src/test-all-functions.js +1 -1
  50. package/dist/src/test-all-functions.js.map +1 -1
  51. package/dist/src/types/mcp-tools.d.ts +2 -2
  52. package/dist/src/types/tool-visibility.js +1 -1
  53. package/dist/src/types/tool-visibility.js.map +1 -1
  54. package/dist/src/utils/cli-detector.d.ts +3 -6
  55. package/dist/src/utils/cli-detector.js +19 -2
  56. package/dist/src/utils/cli-detector.js.map +1 -1
  57. package/dist/src/utils/display-protocol.d.ts +2 -2
  58. package/dist/src/utils/display-protocol.js +4 -4
  59. package/dist/src/utils/display-protocol.js.map +1 -1
  60. package/dist/src/utils/faf-cli-bridge.d.ts +47 -0
  61. package/dist/src/utils/faf-cli-bridge.js +101 -0
  62. package/dist/src/utils/faf-cli-bridge.js.map +1 -0
  63. package/dist/src/utils/visual-style.js +1 -1
  64. package/dist/src/utils/visual-style.js.map +1 -1
  65. package/package.json +7 -10
  66. package/project.faf +31 -133
  67. package/scripts/check-stylesheet-drift.mjs +114 -0
@@ -53,13 +53,16 @@ const version_js_1 = require("../version.js");
53
53
  const visibility_js_1 = require("../config/visibility.js");
54
54
  const tool_registry_js_1 = require("./tool-registry.js");
55
55
  const auto_path_detection_js_1 = require("../utils/auto-path-detection.js");
56
+ // Single source: faf-cli's real scorer + project.html renderer. handleDisplay
57
+ // MUST use these — never reimplement scoring or HTML (kills divergence).
58
+ const faf_cli_1 = require("faf-cli");
56
59
  // 🏆 FAF Score uses the 3-3-1 system: 3 lines, 3 words, 1 emoji!
57
60
  // 💥 Format-Finder (FF) integration for GAME-CHANGING stack detection!
58
- // Claude Desktop filesystem context instruction
61
+ // your MCP host filesystem context instruction
59
62
  const FILESYSTEM_CONTEXT_INSTRUCTION = `
60
63
  CRITICAL CONTEXT FOR CLAUDE DESKTOP:
61
64
  - This MCP server executes on the USER'S REAL FILESYSTEM
62
- - NOT in Claude Desktop's container (/home/claude)
65
+ - NOT in your MCP host's container (/home/claude)
63
66
  - All paths are REAL system paths (/Users/username/ on macOS, /home/username/ on Linux, C:\\ on Windows)
64
67
  - When discussing file locations, use the user's actual filesystem paths, not container paths
65
68
  `;
@@ -201,7 +204,7 @@ Working on REAL filesystem: ${targetDir}
201
204
  },
202
205
  {
203
206
  name: 'faf_display',
204
- description: '🖼️ FAF Display - Generate HTML file showing your ACTUAL score with colors!',
207
+ description: '🖼️ Render project.faf → project.html (faf-cli\'s real scorer + renderer the same context your AI reads)',
205
208
  inputSchema: {
206
209
  type: 'object',
207
210
  properties: {
@@ -520,7 +523,7 @@ Working on REAL filesystem: ${targetDir}
520
523
  },
521
524
  {
522
525
  name: 'faf_guide',
523
- description: 'FAF MCP usage guide for Claude Desktop - Projects convention, path resolution, and UX patterns',
526
+ description: 'FAF MCP usage guide for your MCP host - Projects convention, path resolution, and UX patterns',
524
527
  inputSchema: {
525
528
  type: 'object',
526
529
  properties: {},
@@ -1028,11 +1031,11 @@ Working on REAL filesystem: ${targetDir}
1028
1031
  async handleInit(args) {
1029
1032
  try {
1030
1033
  const dir = args.directory || process.cwd();
1031
- // 🚨 Claude Desktop Protection: Detect root filesystem
1034
+ // 🚨 your MCP host Protection: Detect root filesystem
1032
1035
  if (dir === '/' || dir === '') {
1033
1036
  const helpMessage = `🚨 Directory Required!
1034
1037
 
1035
- Claude Desktop needs a target directory:
1038
+ your MCP host needs a target directory:
1036
1039
 
1037
1040
  **Usage**:
1038
1041
  faf_init directory=/Users/wolfejam/my-project
@@ -1040,7 +1043,7 @@ Claude Desktop needs a target directory:
1040
1043
  **Example**:
1041
1044
  faf_init directory=/Users/wolfejam/GALLERY-SVELTE
1042
1045
 
1043
- 📁 Can't determine working directory automatically in Claude Desktop.
1046
+ 📁 Can't determine working directory automatically in your MCP host.
1044
1047
  ⚠️ Root filesystem (/) is read-only - specify your project path!`;
1045
1048
  return await this.formatResult('🚀 FAF Init', helpMessage);
1046
1049
  }
@@ -1073,117 +1076,24 @@ Claude Desktop needs a target directory:
1073
1076
  }
1074
1077
  }
1075
1078
  async handleDisplay(args) {
1076
- // Generate HTML display of FAF score (v1.2.0: supports project.faf)
1079
+ // Single-sourced render of project.faf HTML. Same pipeline as
1080
+ // faf-cli's `faf show` / `faf export --html`: the real scorer + the
1081
+ // canonical project.html renderer. No reimplementation, no fake
1082
+ // file-presence score, no divergent template.
1077
1083
  const targetDir = args?.directory || process.cwd();
1078
- const outputPath = args?.output || path.join(targetDir, 'faf-score-display.html');
1079
- // Calculate score using v1.2.0 file finder
1080
- let score = 0;
1081
- const fafResult = await (0, faf_file_finder_js_1.findFafFile)(targetDir);
1082
- if (fafResult)
1083
- score += 40;
1084
- const hasClaude = await this.fileExists(path.join(targetDir, 'CLAUDE.md'));
1085
- if (hasClaude)
1086
- score += 30;
1087
- const hasReadme = await this.fileExists(path.join(targetDir, 'README.md'));
1088
- if (hasReadme)
1089
- score += 15;
1090
- const hasPackage = await this.fileExists(path.join(targetDir, 'package.json'));
1091
- if (hasPackage)
1092
- score += 14;
1093
- // Generate 3-3-1 display
1094
- const barWidth = 24;
1095
- const filled = Math.round((score / 100) * barWidth);
1096
- const empty = barWidth - filled;
1097
- const progressBar = '█'.repeat(filled) + '░'.repeat(empty);
1098
- let status = '';
1099
- let emoji = '';
1100
- if (score >= 99) {
1101
- status = 'Trophy!';
1102
- emoji = '🏆';
1103
- }
1104
- else if (score >= 90) {
1105
- status = 'Excellent!';
1106
- emoji = '🧡';
1107
- }
1108
- else if (score >= 70) {
1109
- status = 'Very Good';
1110
- emoji = '⭐';
1111
- }
1112
- else if (score >= 60) {
1113
- status = 'Good Progress';
1114
- emoji = '📈';
1115
- }
1116
- else {
1117
- status = 'Building Up';
1118
- emoji = '🚀';
1119
- }
1120
- // Create HTML with ACTUAL output display
1121
- const html = `<!DOCTYPE html>
1122
- <html>
1123
- <head>
1124
- <meta charset="UTF-8">
1125
- <title>FAF Score - ${path.basename(targetDir)}</title>
1126
- <style>
1127
- body {
1128
- background: #000;
1129
- color: #fff;
1130
- font-family: 'Courier New', 'Monaco', 'Menlo', monospace;
1131
- font-size: 14px;
1132
- padding: 40px;
1133
- line-height: 1.4;
1134
- }
1135
- pre {
1136
- background: #111;
1137
- padding: 30px;
1138
- border-radius: 8px;
1139
- border: 1px solid #333;
1140
- font-family: inherit;
1141
- white-space: pre;
1142
- word-spacing: normal;
1143
- letter-spacing: normal;
1144
- }
1145
- .cyan { color: #00ffff; font-weight: bold; }
1146
- .orange { color: #ff6b35; }
1147
- .green { color: #00bf63; }
1148
- h1 { color: #ff6b35; }
1149
- .footer {
1150
- border-top: 1px solid #666;
1151
- border-bottom: 1px solid #666;
1152
- padding: 10px 0;
1153
- margin: 20px 0;
1154
- font-family: inherit;
1155
- }
1156
- </style>
1157
- </head>
1158
- <body>
1159
- <h1>FAF Score Display - ACTUAL Output!</h1>
1160
- <p>Generated: ${new Date().toISOString()}</p>
1161
- <pre>📊 FAF Score (${path.basename(targetDir)}) 🏎️ 1ms
1162
-
1163
- 🧡 <span class="cyan">Score: ${score}/100</span>
1164
- ${progressBar} ${score}%
1165
- ${emoji} <span class="cyan">Status: ${status}</span>
1166
-
1167
- Breakdown:
1168
- • FAF: ${fafResult ? `☑️ ${fafResult.filename}` : '❌'} ${fafResult ? '40pts' : 'Missing'}
1169
- • CLAUDE.md: ${hasClaude ? '☑️' : '❌'} ${hasClaude ? '30pts' : 'Missing'}
1170
- • README.md: ${hasReadme ? '☑️' : '❌'} ${hasReadme ? '15pts' : 'Missing'}
1171
- • package.json: ${hasPackage ? '☑️' : '❌'} ${hasPackage ? '14pts' : 'Missing'}
1172
-
1173
- <div class="footer">━━━━━━━━━━━━━━━━━━━━━
1174
- AI-Readiness: ${score}% ${emoji}
1175
- ━━━━━━━━━━━━━━━━━━━━━</div></pre>
1176
-
1177
- <p style="color:#666; margin-top:40px;">
1178
- This HTML shows EXACTLY what FAF outputs - no Claude interpretation!<br>
1179
- The score, colors, and footer are all REAL and VISIBLE.
1180
- </p>
1181
- </body>
1182
- </html>`;
1183
- // Write the HTML file
1084
+ const fafPath = (0, faf_cli_1.findFafFile)(targetDir);
1085
+ if (!fafPath) {
1086
+ return await this.formatResult('🖼️ FAF Display', `No .faf found in ${targetDir}\n\n` +
1087
+ `Run faf_init to create one, then faf_display to render it.`);
1088
+ }
1089
+ const data = (0, faf_cli_1.readFaf)(fafPath);
1090
+ const result = (0, faf_cli_1.scoreFafYaml)((0, faf_cli_1.readFafRaw)(fafPath));
1091
+ const html = (0, faf_cli_1.generateProjectHtml)(data, result, fafPath);
1092
+ const outputPath = args?.output || path.join(targetDir, 'project.html');
1184
1093
  await fs.writeFile(outputPath, html);
1185
- return await this.formatResult('🖼️ FAF Display Generated', `HTML file created: ${outputPath}\n\n` +
1186
- `Open in browser to see your ACTUAL score with colors!\n` +
1094
+ return await this.formatResult('🖼️ FAF Display Generated', `Rendered project.faf ${outputPath}\n\n` +
1095
+ `Single-sourced from faf-cli the real scorer and renderer, ` +
1096
+ `the same truth your AI reads.\n` +
1187
1097
  `file://${outputPath}`);
1188
1098
  }
1189
1099
  async handleShow(args) {
@@ -1191,82 +1101,33 @@ AI-Readiness: ${score}% ${emoji}
1191
1101
  const command = args.command || 'score';
1192
1102
  const directory = args.directory || process.cwd();
1193
1103
  if (command === 'score') {
1194
- // Get the clean score data
1195
1104
  const targetDir = directory;
1196
- // Calculate score (using same logic as handleScore)
1197
- let score = 0;
1198
- let hasFaf = false;
1199
- let hasClaude = false;
1200
- let hasReadme = false;
1201
- let hasPackage = false;
1202
- // Check files (v1.2.0: supports project.faf)
1203
- const fafResult = await (0, faf_file_finder_js_1.findFafFile)(targetDir);
1204
- hasFaf = fafResult !== null;
1205
- if (hasFaf)
1206
- score += 40;
1207
- hasClaude = await this.fileExists(path.join(targetDir, 'CLAUDE.md'));
1208
- if (hasClaude)
1209
- score += 30;
1210
- hasReadme = await this.fileExists(path.join(targetDir, 'README.md'));
1211
- if (hasReadme)
1212
- score += 15;
1213
- hasPackage = await this.fileExists(path.join(targetDir, 'package.json'));
1214
- if (hasPackage)
1215
- score += 14;
1216
- // Build CLEAN markdown - no wrappers!
1217
- const progressBar = '█'.repeat(Math.floor(score * 24 / 100)) + '░'.repeat(24 - Math.floor(score * 24 / 100));
1218
- // Mk3 Canonical Tier System
1219
- const { medal: statusEmoji, status: statusText } = this.getScoreMedal(score);
1220
- // Build clean output - just markdown, no wrappers!
1105
+ const s = this.getFafScore(targetDir);
1106
+ if (!s.found) {
1107
+ return display_protocol_js_1.DisplayProtocol.createResponse(`# FAF Score Card\n\n` +
1108
+ `No \`.faf\` found in \`${targetDir}\`.\n\n` +
1109
+ `Run \`faf_init\` to create one — then \`faf_show\` renders the real score.`, { tool: 'faf_show', command });
1110
+ }
1111
+ const barWidth = 24;
1112
+ const filled = Math.round((s.score / 100) * barWidth);
1113
+ const progressBar = '█'.repeat(filled) + '░'.repeat(barWidth - filled);
1221
1114
  const output = `# FAF Score Card
1222
1115
 
1223
- ## **Project Score: ${score}/100** ${statusEmoji}
1224
-
1225
- ${progressBar} ${score}%
1226
-
1227
- ### ${statusEmoji} **Status: ${statusText}**
1228
-
1229
- ---
1230
-
1231
- ## 📊 Performance Breakdown
1232
-
1233
- | Component | Status | Points | Performance |
1234
- |-----------|--------|--------|-------------|
1235
- | **.faf** | ${hasFaf ? '✅ **ACTIVE**' : '❌ **MISSING**'} | ${hasFaf ? '40' : '0'}pts | ${hasFaf ? 'Core config synchronized' : 'Create with faf_init'} |
1236
- | **CLAUDE.md** | ${hasClaude ? '✅ **SYNCED**' : '❌ **MISSING**'} | ${hasClaude ? '30' : '0'}pts | ${hasClaude ? 'AI documentation live' : 'Generate with faf_sync'} |
1237
- | **README.md** | ${hasReadme ? '✅ **READY**' : '❌ **MISSING**'} | ${hasReadme ? '15' : '0'}pts | ${hasReadme ? 'Project docs complete' : 'Add for extra points'} |
1238
- | **package.json** | ${hasPackage ? '✅ **FOUND**' : '❌ **MISSING**'} | ${hasPackage ? '14' : '0'}pts | ${hasPackage ? 'Dependencies tracked' : 'Add for full score'} |
1239
-
1240
- ---
1116
+ ## **${s.score}/100** ${s.tierDisplay}
1241
1117
 
1242
- ## Context Status
1118
+ ${progressBar} ${s.score}%
1243
1119
 
1244
- ### **Strengths** 💚
1245
- ${hasFaf && hasClaude ? '- Bi-directional sync active\n' : ''}${hasClaude ? '- AI-Ready Documentation: Full CLAUDE.md integration\n' : ''}${hasFaf ? '- Core Systems: FAF foundation in place\n' : ''}${hasReadme ? '- Documentation: README.md providing clarity\n' : ''}${hasPackage ? '- Dependencies: package.json tracking enabled' : ''}
1120
+ ${s.populated}/${s.total} slots populated${s.nextTier ? ` · next: ${s.nextTier}` : ' · top tier'}
1246
1121
 
1247
1122
  ---
1248
1123
 
1249
- ## Quick Commands
1124
+ > Scored by faf-cli's real scorer — the same context your AI reads.
1125
+ > For slot-by-slot detail run \`faf score\` (faf-cli).
1250
1126
 
1251
- \`\`\`bash
1252
- faf_bi_sync # Keep files synchronized
1253
- faf_enhance # AI-powered improvements
1254
- faf_score --save # Save this scorecard
1255
- \`\`\`
1256
-
1257
- ---
1258
-
1259
- > "Context is everything. FAF delivers it."
1260
-
1261
- ---
1262
-
1263
- **AI-Readiness: ${score}%** ${score >= 99 ? '🏆' : ''}`;
1264
- // 🍫 CHOCOLATE ORANGE - UNWRAPPED AND READY!
1265
- // Use DisplayProtocol for consistent global rendering
1127
+ **AI-Readiness: ${s.score}%**`;
1266
1128
  return display_protocol_js_1.DisplayProtocol.createResponse(output, {
1267
1129
  tool: 'faf_show',
1268
- command: command,
1269
- timestamp: new Date().toISOString()
1130
+ command,
1270
1131
  });
1271
1132
  }
1272
1133
  // Default fallback - also use DisplayProtocol
@@ -1276,249 +1137,52 @@ faf_score --save # Save this scorecard
1276
1137
  const targetDir = args?.directory || process.cwd();
1277
1138
  const saveCard = args?.save === true;
1278
1139
  const format = args?.format || 'markdown';
1279
- const showFull = args?.full === true;
1280
- // TRY THE FAF ENGINE FIRST!
1281
- let score = 0;
1282
- let hasFaf = false;
1283
- let hasClaude = false;
1284
- let hasReadme = false;
1285
- let hasPackage = false;
1286
- try {
1287
- this.fafEngine.setWorkingDirectory(targetDir);
1288
- const result = await this.fafEngine.callEngine('score', ['--json']);
1289
- if (result.success && result.data) {
1290
- // Extract score from engine response
1291
- if (typeof result.data.score === 'number') {
1292
- score = result.data.score;
1293
- // Engine should tell us what files contributed
1294
- hasFaf = result.data.files?.faf || false;
1295
- hasClaude = result.data.files?.claude || false;
1296
- hasReadme = result.data.files?.readme || false;
1297
- hasPackage = result.data.files?.package || false;
1298
- }
1299
- else {
1300
- // Parse text output for score
1301
- const outputText = result.data.output || '';
1302
- const scoreMatch = outputText.match(/(\d+)%/);
1303
- if (scoreMatch) {
1304
- score = parseInt(scoreMatch[1]);
1305
- }
1306
- }
1307
- }
1308
- }
1309
- catch (engineError) {
1310
- console.warn('FAF Engine score failed, using native:', engineError);
1140
+ // HTML delegates to the single-sourced renderer (faf-cli's project.html).
1141
+ if (format === 'html') {
1142
+ return await this.handleDisplay({ directory: targetDir, output: path.join(targetDir, 'SCORE-CARD.html') });
1311
1143
  }
1312
- // If engine failed or gave no score, calculate natively (v1.2.0: supports project.faf)
1313
- if (score === 0) {
1314
- const fafResult = await (0, faf_file_finder_js_1.findFafFile)(targetDir);
1315
- hasFaf = fafResult !== null;
1316
- if (hasFaf)
1317
- score += 40;
1318
- hasClaude = await this.fileExists(path.join(targetDir, 'CLAUDE.md'));
1319
- if (hasClaude)
1320
- score += 30;
1321
- hasReadme = await this.fileExists(path.join(targetDir, 'README.md'));
1322
- if (hasReadme)
1323
- score += 15;
1324
- hasPackage = await this.fileExists(path.join(targetDir, 'package.json'));
1325
- if (hasPackage)
1326
- score += 14;
1144
+ const sc = this.getFafScore(targetDir);
1145
+ if (!sc.found) {
1146
+ return await this.formatResult('🏎️ FAF Score', `No \`.faf\` found in \`${targetDir}\`.\n\nRun \`faf_init\` to create one.`, undefined, targetDir);
1327
1147
  }
1328
- // Generate scorecard based on format
1148
+ const barWidth = 24;
1149
+ const filled = Math.round((sc.score / 100) * barWidth);
1150
+ const progressBar = '█'.repeat(filled) + '░'.repeat(barWidth - filled);
1329
1151
  let result = '';
1330
1152
  if (format === 'json') {
1331
- // JSON format
1332
1153
  result = JSON.stringify({
1333
1154
  project: path.basename(targetDir),
1334
- score: score,
1335
- percentage: score,
1336
- status: this.getScoreMedal(score).status,
1337
- components: {
1338
- faf: { exists: hasFaf, points: hasFaf ? 40 : 0 },
1339
- claude: { exists: hasClaude, points: hasClaude ? 30 : 0 },
1340
- readme: { exists: hasReadme, points: hasReadme ? 15 : 0 },
1341
- package: { exists: hasPackage, points: hasPackage ? 14 : 0 }
1342
- },
1343
- ai_readiness: score,
1344
- timestamp: new Date().toISOString(),
1345
- version: version_js_1.VERSION
1155
+ score: sc.score,
1156
+ tier: sc.tierName,
1157
+ slots: { populated: sc.populated, total: sc.total },
1158
+ next_tier: sc.nextTier,
1159
+ source: 'faf-cli',
1160
+ version: version_js_1.VERSION,
1346
1161
  }, null, 2);
1347
1162
  }
1348
- else if (format === 'html') {
1349
- // HTML format (delegate to display handler)
1350
- return await this.handleDisplay({ directory: targetDir, output: path.join(targetDir, 'SCORE-CARD.html') });
1351
- }
1352
1163
  else if (format === 'ascii') {
1353
- // Simple ASCII format
1354
- const barWidth = 24;
1355
- const filled = Math.round((score / 100) * barWidth);
1356
- const empty = barWidth - filled;
1357
- const progressBar = '█'.repeat(filled) + '░'.repeat(empty);
1358
- result = `FAF Score: ${score}/100\n`;
1359
- result += `${progressBar} ${score}%\n`;
1360
- result += `[.faf: ${hasFaf ? '✓' : 'x'}] [CLAUDE.md: ${hasClaude ? '✓' : 'x'}] [README: ${hasReadme ? '✓' : 'x'}] [package.json: ${hasPackage ? '✓' : 'x'}]`;
1361
- }
1362
- else if (showFull) {
1363
- // Podium Edition: Full Championship Scorecard with detailed metrics
1364
- const _projectName = path.basename(targetDir);
1365
- // Calculate section scores based on files present
1366
- const coreIntelligence = Math.round(((hasFaf ? 25 : 0) +
1367
- (hasFaf && hasClaude ? 25 : 0) + // Architecture Map (requires both)
1368
- (hasFaf ? 25 : 0) + // Domain Model
1369
- (hasFaf ? 25 : 0) // Version Tracking
1370
- ));
1371
- const contextDelivery = Math.round((25 + // MCP Protocol (always active)
1372
- 25 + // 50 Native Tools (always active)
1373
- 25 + // IANA Format (always active)
1374
- (hasFaf && hasClaude ? 25 : hasFaf ? 15 : hasClaude ? 10 : 0) // Universal Context
1375
- ));
1376
- const _performance = 100; // Static for MCP server itself
1377
- const _standalone = 100; // Static for MCP server itself
1378
- // Determine status tier
1379
- // Mk3 Canonical Tier System
1380
- const { medal: tierEmoji, status: statusTier } = this.getScoreMedal(score);
1381
- result = ``;
1382
- result += `# FAF AI-Readiness Score: ${score}/100 ${tierEmoji}\n\n`;
1383
- result += `**The closer you get to 100% the better AI can assist you.**\n\n`;
1384
- result += `At 55% you are building your project with half a blueprint and basically flipping a coin with AI. .FAF defines, and AI becomes optimized for Context with the project.faf file.\n\n`;
1385
- result += `\`\`\`\n`;
1386
- result += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`;
1387
- result += `${tierEmoji} FAF AI-READINESS SCORE: ${score}/100 — ${statusTier}\n`;
1388
- result += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n`;
1389
- // Core Intelligence section
1390
- result += `📊 CORE INTELLIGENCE 🎯 CONTEXT DELIVERY\n`;
1391
- const bar100 = '[██████] 100%';
1392
- const _barCore = `[${('█'.repeat(Math.round(coreIntelligence / 100 * 6)) + '░'.repeat(6 - Math.round(coreIntelligence / 100 * 6)))}] ${coreIntelligence}%`;
1393
- const barContext = `[${('█'.repeat(Math.round(contextDelivery / 100 * 6)) + '░'.repeat(6 - Math.round(contextDelivery / 100 * 6)))}] ${contextDelivery}%`;
1394
- result += `├─ Project DNA ${hasFaf ? bar100 : '[░░░░░░] 0%'} ├─ MCP Protocol ${bar100}\n`;
1395
- result += `├─ Architecture Map ${hasFaf && hasClaude ? bar100 : '[░░░░░░] 0%'} ├─ 50 Native Tools ${bar100}\n`;
1396
- result += `├─ Domain Model ${hasFaf ? bar100 : '[░░░░░░] 0%'} ├─ IANA Format ${bar100}\n`;
1397
- result += `└─ Version Tracking ${hasFaf ? bar100 : '[░░░░░░] 0%'} └─ Universal Context ${barContext}\n\n`;
1398
- // Performance section
1399
- result += `🚀 PERFORMANCE ⚡ STANDALONE OPERATION\n`;
1400
- result += `├─ 16.2x CLI Speedup ${bar100} ├─ Zero Dependencies ${bar100}\n`;
1401
- result += `├─ 19ms Avg Execution ${bar100} ├─ Bundled Engine ${bar100}\n`;
1402
- result += `├─ 50/50 Tools Active ${bar100} ├─ Direct Function ${bar100}\n`;
1403
- result += `└─ Zero Memory Leaks ${bar100} └─ 14 Bundled Cmds ${bar100}\n\n`;
1404
- result += `${tierEmoji} project.faf score: ${statusTier}\n`;
1405
- result += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`;
1406
- result += `\`\`\`\n\n`;
1407
- // Next steps
1408
- result += `## ⚡ Next Steps\n\n`;
1409
- if (!hasFaf) {
1410
- result += `🚀 **Initialize FAF**: Run \`faf_init\` to create project.faf (+40 points)\n\n`;
1411
- }
1412
- if (!hasClaude) {
1413
- result += `📝 **Generate CLAUDE.md**: Run \`faf_sync\` to create AI documentation (+30 points)\n\n`;
1414
- }
1415
- if (hasFaf && hasClaude) {
1416
- result += `🎯 **You're at 100%!** Run \`faf_bi_sync\` to keep files synchronized.\n\n`;
1417
- }
1418
- result += `---\n\n`;
1419
- result += `*Generated by FAF v${version_js_1.VERSION}*\n\n`;
1420
- result += `*"It's so logical if it didn't exist, AI would have built it itself" — Claude*`;
1164
+ result =
1165
+ `FAF Score: ${sc.score}/100 ${sc.tierDisplay}\n` +
1166
+ `${progressBar} ${sc.score}%\n` +
1167
+ `${sc.populated}/${sc.total} slots${sc.nextTier ? ` next: ${sc.nextTier}` : ' top tier'}`;
1421
1168
  }
1422
1169
  else {
1423
- // Default: Beautiful Markdown Championship Scorecard
1424
- const barWidth = 24;
1425
- const filled = Math.round((score / 100) * barWidth);
1426
- const empty = barWidth - filled;
1427
- const progressBar = '█'.repeat(filled) + '░'.repeat(empty);
1428
- // Determine status and emoji
1429
- let statusEmoji = '';
1430
- let statusText = '';
1431
- // Mk3 Canonical Tier System
1432
- const { medal, status } = this.getScoreMedal(score);
1433
- statusEmoji = medal;
1434
- statusText = status;
1435
- // Build the scorecard
1436
- result = `# FAF Score Card\n\n`;
1437
- result += `## **Project Score: ${score}/100** ${statusEmoji}\n\n`;
1438
- result += `${progressBar} ${score}%\n\n`;
1439
- result += `### ${statusEmoji} **Status: ${statusText}**\n\n`;
1440
- result += `---\n\n`;
1441
- // Performance Breakdown Table
1442
- result += `## 📊 Performance Breakdown\n\n`;
1443
- result += `| Component | Status | Points | Performance |\n`;
1444
- result += `|-----------|--------|--------|-------------|\n`;
1445
- result += `| **.faf** | ${hasFaf ? '✅ **ACTIVE**' : '⚠️ **MISSING**'} | ${hasFaf ? '40' : '0'}pts | ${hasFaf ? 'Core config synchronized' : '*Create with `faf_init`*'} |\n`;
1446
- result += `| **CLAUDE.md** | ${hasClaude ? '✅ **SYNCED**' : '⚠️ **MISSING**'} | ${hasClaude ? '30' : '0'}pts | ${hasClaude ? 'AI documentation live' : '*Generate with `faf_sync`*'} |\n`;
1447
- result += `| **README.md** | ${hasReadme ? '✅ **READY**' : '⚠️ **MISSING**'} | ${hasReadme ? '15' : '0'}pts | ${hasReadme ? 'Project docs complete' : '*Add for extra points*'} |\n`;
1448
- result += `| **package.json** | ${hasPackage ? '✅ **FOUND**' : '⚠️ **MISSING**'} | ${hasPackage ? '14' : '0'}pts | ${hasPackage ? 'Dependencies tracked' : '*Add for full score*'} |\n`;
1449
- result += `\n---\n\n`;
1450
- // Context Status Section
1451
- result += `## Context Status\n\n`;
1452
- // Strengths
1453
- const strengths = [];
1454
- if (hasFaf && hasClaude)
1455
- strengths.push('Bi-directional sync active');
1456
- if (hasClaude)
1457
- strengths.push('AI-Ready Documentation: Full CLAUDE.md integration');
1458
- if (hasFaf)
1459
- strengths.push('Core Systems: FAF foundation in place');
1460
- if (hasReadme)
1461
- strengths.push('Documentation: README.md providing clarity');
1462
- if (hasPackage)
1463
- strengths.push('Dependencies: package.json tracking enabled');
1464
- if (strengths.length > 0) {
1465
- result += `### **Strengths** 💚\n`;
1466
- strengths.forEach(s => result += `- ${s}\n`);
1467
- result += `\n`;
1468
- }
1469
- // Improvements needed
1470
- const improvements = [];
1471
- if (!hasFaf)
1472
- improvements.push('Initialize with `faf_init` for +40 points');
1473
- if (!hasClaude)
1474
- improvements.push('Create CLAUDE.md with `faf_sync` for +30 points');
1475
- if (!hasReadme)
1476
- improvements.push('Add README.md for +15 points → better documentation');
1477
- if (!hasPackage)
1478
- improvements.push('Add package.json for +14 points → ${score + 14}% score');
1479
- if (improvements.length > 0) {
1480
- result += `### **Improvements Needed** 🔧\n`;
1481
- improvements.forEach(i => result += `- ${i}\n`);
1482
- result += `\n`;
1483
- }
1484
- // Quick Commands
1485
- result += `---\n\n`;
1486
- result += `## ⚡ Quick Commands\n\n`;
1487
- result += `\`\`\`bash\n`;
1488
- if (!hasFaf)
1489
- result += `faf_init # Initialize FAF (+40 pts)\n`;
1490
- if (!hasClaude)
1491
- result += `faf_sync # Generate CLAUDE.md (+30 pts)\n`;
1492
- if (hasFaf && hasClaude)
1493
- result += `faf_bi_sync # Keep files synchronized\n`;
1494
- result += `faf_enhance # AI-powered improvements\n`;
1495
- result += `faf_score --save # Save this scorecard\n`;
1496
- result += `\`\`\`\n\n`;
1497
- // FAF Quote
1498
- const quotes = [
1499
- '"Context is everything. FAF delivers it."',
1500
- '"Stop FAFfing about - get to 100%!"',
1501
- '"The best time to FAF was yesterday. The second best time is now."',
1502
- '"AI without context is just guessing."',
1503
- '"One file. Complete understanding."'
1504
- ];
1505
- const randomQuote = quotes[Math.floor(Math.random() * quotes.length)];
1506
- result += `---\n\n`;
1507
- result += `> ${randomQuote}\n\n`;
1508
- // Footer
1509
- result += `---\n\n`;
1510
- result += `*Generated by FAF v${version_js_1.VERSION}* ⚡\n`;
1511
- result += `*${new Date().toISOString()}*`;
1512
- // NOTE: AI-Readiness footer is added by formatResult() - don't duplicate!
1513
- }
1514
- // Save scorecard if requested
1515
- if (saveCard) {
1170
+ // markdown (default). `full` adds nothing fabricated — the real
1171
+ // score IS the full truth; the old championship theater is dead.
1172
+ result =
1173
+ `# FAF Score Card\n\n` +
1174
+ `## **${sc.score}/100** ${sc.tierDisplay}\n\n` +
1175
+ `${progressBar} ${sc.score}%\n\n` +
1176
+ `**${sc.populated}/${sc.total} slots populated**${sc.nextTier ? ` · next: ${sc.nextTier}` : ' · top tier'}\n\n` +
1177
+ `---\n\n` +
1178
+ `> Scored by faf-cli's real scorer — the same context your AI reads.\n` +
1179
+ `> Slot-by-slot detail: \`faf score\` (faf-cli).`;
1180
+ }
1181
+ if (saveCard && format !== 'json') {
1516
1182
  const scoreCardPath = path.join(targetDir, 'SCORE-CARD.md');
1517
- await fs.writeFile(scoreCardPath, result.replace(/\\n/g, '\n'));
1183
+ await fs.writeFile(scoreCardPath, result);
1518
1184
  result += `\n\n✅ **Score card saved to:** \`${scoreCardPath}\``;
1519
1185
  }
1520
- // ✅ FIXED - Route through formatResult for metadata!
1521
- // formatResult will add the universal AI-Readiness footer
1522
1186
  return await this.formatResult('🏎️ FAF Score', result, undefined, targetDir);
1523
1187
  }
1524
1188
  async handleSync(args) {
@@ -2011,7 +1675,7 @@ faf_score --save # Save this scorecard
2011
1675
  answer = `🔧 TROUBLESHOOTING\n\n` +
2012
1676
  `"EROFS: read-only file system"\n` +
2013
1677
  `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n` +
2014
- `You're in Claude Desktop sandbox!\n` +
1678
+ `You're in your MCP host sandbox!\n` +
2015
1679
  `Solution: Use real path\n` +
2016
1680
  `Example: faf_auto ~/Documents/project\n\n` +
2017
1681
  `"Stack: Unknown"\n` +
@@ -2069,11 +1733,11 @@ faf_score --save # Save this scorecard
2069
1733
  return await this.formatResult('💡 FAF HELP', answer);
2070
1734
  }
2071
1735
  async handleGuide(_args) {
2072
- const guide = `# FAF MCP - Claude Desktop Guide
1736
+ const guide = `# FAF MCP - your MCP host Guide
2073
1737
 
2074
1738
  ## Core Principle: Local Path First
2075
1739
 
2076
- Claude Desktop has full filesystem access with local paths. All 52 MCP tools work perfectly when you provide local project paths.
1740
+ your MCP host has full filesystem access with local paths. All 52 MCP tools work perfectly when you provide local project paths.
2077
1741
 
2078
1742
  **The Pattern:**
2079
1743
  1. Ask: "What's your project path?"
@@ -2139,106 +1803,50 @@ Simple, fast, championship-grade.`;
2139
1803
  // Developer Tool Handlers
2140
1804
  async handleStatus(args) {
2141
1805
  const targetDir = args?.directory || process.cwd();
2142
- // Calculate score
2143
- const score = await this.calculateScore(targetDir);
2144
- // Get medal from Championship Medal System (matching CLI)
2145
- const { medal } = this.getScoreMedal(score);
2146
- // Get next target info
2147
- const tierInfo = this.getTierInfo(score);
2148
- // Build status output
2149
- let output = `🏎️ FAF Status\n━━━━━━━━━━━━\n`;
2150
- output += `Score: ${score}% ${medal} ${tierInfo.current}\n`;
2151
- if (tierInfo.next && tierInfo.nextTarget && tierInfo.nextMedal) {
2152
- const pointsToGo = tierInfo.nextTarget - score;
2153
- output += `Next: ${tierInfo.nextTarget}% ${tierInfo.nextMedal} ${tierInfo.next} (${pointsToGo}% to go!)`;
1806
+ const s = this.getFafScore(targetDir);
1807
+ if (!s.found) {
1808
+ return await this.formatResult('📊 FAF Status', `No \`.faf\` in \`${targetDir}\`. Run \`faf_init\` to create one.`, undefined, targetDir);
2154
1809
  }
1810
+ let output = `🏎️ FAF Status\n━━━━━━━━━━━━\n`;
1811
+ output += `Score: ${s.score}% ${s.tierDisplay}\n`;
1812
+ output += `Slots: ${s.populated}/${s.total} populated\n`;
1813
+ output += s.nextTier ? `Next: ${s.nextTier}` : `Top tier — nothing above.`;
2155
1814
  return await this.formatResult('📊 FAF Status', output, undefined, targetDir);
2156
1815
  }
2157
1816
  /**
2158
- * Get championship medal emoji and status based on score
2159
- * Matches CLI medal system exactly
1817
+ * Single source of truth for score + tier: faf-cli's real scorer and
1818
+ * canonical tier ladder (~/FAF/cli/src/core/tiers.ts). NEVER reimplement
1819
+ * scoring or the tier symbols here — the old file-presence pseudo-score
1820
+ * (40/30/15/14) and the banned medal/colored-circle ladder are dead.
2160
1821
  */
2161
- getScoreMedal(score) {
2162
- if (score >= 100)
2163
- return { medal: '🏆', status: 'Trophy - Championship' };
2164
- if (score >= 99)
2165
- return { medal: '🥇', status: 'Gold' };
2166
- if (score >= 95)
2167
- return { medal: '🥈', status: 'Silver' };
2168
- if (score >= 85)
2169
- return { medal: '🥉', status: 'Bronze' };
2170
- if (score >= 70)
2171
- return { medal: '🟢', status: 'Green - Solid foundation' };
2172
- if (score >= 55)
2173
- return { medal: '🟡', status: 'Yellow - Needs improvement' };
2174
- if (score > 0)
2175
- return { medal: '🔴', status: 'Red - AI working blind' };
2176
- return { medal: '🤍', status: 'White - Empty' };
2177
- }
2178
- /**
2179
- * Get tier progression info
2180
- * Shows current tier and next target
2181
- */
2182
- getTierInfo(score) {
2183
- if (score >= 100) {
2184
- return { current: 'Trophy - Championship' };
2185
- }
2186
- else if (score >= 99) {
1822
+ getFafScore(dir) {
1823
+ // eslint-disable-next-line no-control-regex
1824
+ const strip = (s) => s.replace(/\u001b\[[0-9;]*m/g, "").trim();
1825
+ const fafPath = (0, faf_cli_1.findFafFile)(dir);
1826
+ if (!fafPath) {
2187
1827
  return {
2188
- current: 'Gold',
2189
- next: 'Trophy - Championship',
2190
- nextTarget: 100,
2191
- nextMedal: '🏆'
2192
- };
2193
- }
2194
- else if (score >= 95) {
2195
- return {
2196
- current: 'Silver',
2197
- next: 'Gold',
2198
- nextTarget: 99,
2199
- nextMedal: '🥇'
2200
- };
2201
- }
2202
- else if (score >= 85) {
2203
- return {
2204
- current: 'Bronze',
2205
- next: 'Silver',
2206
- nextTarget: 95,
2207
- nextMedal: '🥈'
2208
- };
2209
- }
2210
- else if (score >= 70) {
2211
- return {
2212
- current: 'Green - Solid foundation',
2213
- next: 'Bronze',
2214
- nextTarget: 85,
2215
- nextMedal: '🥉'
2216
- };
2217
- }
2218
- else if (score >= 55) {
2219
- return {
2220
- current: 'Yellow - Needs improvement',
2221
- next: 'Green - Solid foundation',
2222
- nextTarget: 70,
2223
- nextMedal: '🟢'
2224
- };
2225
- }
2226
- else if (score > 0) {
2227
- return {
2228
- current: 'Red - AI working blind',
2229
- next: 'Yellow - Needs improvement',
2230
- nextTarget: 55,
2231
- nextMedal: '🟡'
2232
- };
2233
- }
2234
- else {
2235
- return {
2236
- current: 'White - Empty',
2237
- next: 'Red - AI working blind',
2238
- nextTarget: 1,
2239
- nextMedal: '🔴'
1828
+ found: false,
1829
+ score: 0,
1830
+ tierName: 'White',
1831
+ tierGlyph: '',
1832
+ tierDisplay: '♡ no .faf',
1833
+ nextTier: null,
1834
+ populated: 0,
1835
+ total: 0,
2240
1836
  };
2241
1837
  }
1838
+ const r = (0, faf_cli_1.scoreFafYaml)((0, faf_cli_1.readFafRaw)(fafPath));
1839
+ const next = (0, faf_cli_1.getNextTier)(r.score);
1840
+ return {
1841
+ found: true,
1842
+ score: r.score,
1843
+ tierName: r.tier.name,
1844
+ tierGlyph: strip(r.tier.indicator).split(' ')[0] || '',
1845
+ tierDisplay: strip(r.tier.indicator),
1846
+ nextTier: next ? `${strip(next.indicator)} (${next.threshold}%)` : null,
1847
+ populated: r.populated,
1848
+ total: r.total,
1849
+ };
2242
1850
  }
2243
1851
  async handleCheck(_args) {
2244
1852
  return await this.formatResult('✅ FAF Check', 'All systems operational!');
@@ -2526,7 +2134,7 @@ Performance: <50ms per operation
2526
2134
  const startTime = Date.now();
2527
2135
  try {
2528
2136
  // Find the skill file in the npm package
2529
- // It should be at: node_modules/claude-faf-mcp/skill/SKILL.md
2137
+ // It should be at: node_modules/faf-mcp/skill/SKILL.md
2530
2138
  const homeDir = process.env.HOME || process.env.USERPROFILE || '/';
2531
2139
  const claudeSkillsDir = path.join(homeDir, '.claude', 'skills', 'faf-expert');
2532
2140
  const targetSkillPath = path.join(claudeSkillsDir, 'SKILL.md');
@@ -2539,14 +2147,14 @@ Performance: <50ms per operation
2539
2147
  }
2540
2148
  // Location 2: In node_modules (global or local)
2541
2149
  if (!sourceSkillPath) {
2542
- const globalNodeModules = path.join(homeDir, '.npm', 'lib', 'node_modules', 'claude-faf-mcp', 'skill', 'SKILL.md');
2150
+ const globalNodeModules = path.join(homeDir, '.npm', 'lib', 'node_modules', 'faf-mcp', 'skill', 'SKILL.md');
2543
2151
  if (await this.fileExists(globalNodeModules)) {
2544
2152
  sourceSkillPath = globalNodeModules;
2545
2153
  }
2546
2154
  }
2547
2155
  // Location 3: In current working directory node_modules
2548
2156
  if (!sourceSkillPath) {
2549
- const localNodeModules = path.join(process.cwd(), 'node_modules', 'claude-faf-mcp', 'skill', 'SKILL.md');
2157
+ const localNodeModules = path.join(process.cwd(), 'node_modules', 'faf-mcp', 'skill', 'SKILL.md');
2550
2158
  if (await this.fileExists(localNodeModules)) {
2551
2159
  sourceSkillPath = localNodeModules;
2552
2160
  }
@@ -2554,7 +2162,7 @@ Performance: <50ms per operation
2554
2162
  // Location 4: Search using require.resolve
2555
2163
  if (!sourceSkillPath) {
2556
2164
  try {
2557
- const mcpPackageRoot = path.dirname(require.resolve('claude-faf-mcp/package.json'));
2165
+ const mcpPackageRoot = path.dirname(require.resolve('faf-mcp/package.json'));
2558
2166
  const resolvedPath = path.join(mcpPackageRoot, 'skill', 'SKILL.md');
2559
2167
  if (await this.fileExists(resolvedPath)) {
2560
2168
  sourceSkillPath = resolvedPath;
@@ -2566,7 +2174,7 @@ Performance: <50ms per operation
2566
2174
  }
2567
2175
  if (!sourceSkillPath) {
2568
2176
  const duration = Date.now() - startTime;
2569
- return await this.formatResult('🏆 Install faf-expert Skill', `❌ Could not locate skill file in npm package.\n\nSearched:\n- ${devRepoPath}\n- Global node_modules\n- Local node_modules\n\nPlease ensure claude-faf-mcp is installed.`, duration);
2177
+ return await this.formatResult('🏆 Install faf-expert Skill', `❌ Could not locate skill file in npm package.\n\nSearched:\n- ${devRepoPath}\n- Global node_modules\n- Local node_modules\n\nPlease ensure faf-mcp is installed.`, duration);
2570
2178
  }
2571
2179
  // Create directory if needed
2572
2180
  await fs.mkdir(claudeSkillsDir, { recursive: true });
@@ -2577,10 +2185,10 @@ Performance: <50ms per operation
2577
2185
  return await this.formatResult('🏆 Install faf-expert Skill', `✅ faf-expert skill installed successfully!\n\n` +
2578
2186
  `📍 Location: ${targetSkillPath}\n\n` +
2579
2187
  `🔄 RESTART REQUIRED:\n` +
2580
- ` Please restart Claude Desktop to activate the skill.\n\n` +
2188
+ ` Please restart your MCP host to activate the skill.\n\n` +
2581
2189
  `🎯 Once restarted, invoke the faf-expert skill to reach\n` +
2582
2190
  ` 99/100 AI-readiness with championship-grade guidance!\n\n` +
2583
- `💡 Usage: Just say "Invoke faf-expert skill" in Claude Desktop`, duration);
2191
+ `💡 Usage: Just say "Invoke faf-expert skill" in your MCP host`, duration);
2584
2192
  }
2585
2193
  catch (error) {
2586
2194
  const duration = Date.now() - startTime;
@@ -2616,8 +2224,8 @@ Performance: <50ms per operation
2616
2224
  const hasPackage = await this.fileExists(path.join(fullPath, 'package.json'));
2617
2225
  const hasFaf = await (0, faf_file_finder_js_1.hasFafFile)(fullPath);
2618
2226
  if (hasPackage || hasFaf) {
2619
- // Calculate score
2620
- const score = await this.calculateScore(fullPath);
2227
+ // Real faf-cli score (0 when the project has no .faf — honest)
2228
+ const score = this.getFafScore(fullPath).score;
2621
2229
  projects.push({
2622
2230
  name: dir.name,
2623
2231
  path: fullPath,
@@ -2707,22 +2315,6 @@ Performance: <50ms per operation
2707
2315
  timestamp: new Date().toISOString()
2708
2316
  });
2709
2317
  }
2710
- /**
2711
- * Calculate current AI-Readiness score quietly
2712
- */
2713
- async calculateScore(dir) {
2714
- const targetDir = dir || process.cwd();
2715
- let score = 0;
2716
- if (await (0, faf_file_finder_js_1.hasFafFile)(targetDir))
2717
- score += 40;
2718
- if (await this.fileExists(path.join(targetDir, 'CLAUDE.md')))
2719
- score += 30;
2720
- if (await this.fileExists(path.join(targetDir, 'README.md')))
2721
- score += 15;
2722
- if (await this.fileExists(path.join(targetDir, 'package.json')))
2723
- score += 14;
2724
- return score;
2725
- }
2726
2318
  }
2727
2319
  exports.ChampionshipToolHandler = ChampionshipToolHandler;
2728
2320
  //# sourceMappingURL=championship-tools.js.map