faf-mcp 2.3.1 ā 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -3
- package/CLAUDE.md +6 -6
- package/README.md +71 -72
- package/dist/src/faf-core/commands/bi-sync.d.ts +1 -3
- package/dist/src/faf-core/commands/bi-sync.js +21 -64
- package/dist/src/faf-core/commands/bi-sync.js.map +1 -1
- package/dist/src/faf-core/commands/sync.js.map +1 -1
- package/dist/src/faf-core/engines/dependency-tsa.js.map +1 -1
- package/dist/src/faf-core/fix-once/colors.js +1 -1
- package/dist/src/faf-core/fix-once/colors.js.map +1 -1
- package/dist/src/faf-core/parsers/agents-parser.d.ts +15 -0
- package/dist/src/faf-core/parsers/agents-parser.js +29 -123
- package/dist/src/faf-core/parsers/agents-parser.js.map +1 -1
- package/dist/src/faf-core/parsers/conductor-parser.js +1 -1
- package/dist/src/faf-core/parsers/conductor-parser.js.map +1 -1
- package/dist/src/faf-core/parsers/cursorrules-parser.d.ts +15 -0
- package/dist/src/faf-core/parsers/cursorrules-parser.js +54 -111
- package/dist/src/faf-core/parsers/cursorrules-parser.js.map +1 -1
- package/dist/src/faf-core/parsers/faf-git-generator.js +0 -1
- package/dist/src/faf-core/parsers/faf-git-generator.js.map +1 -1
- package/dist/src/faf-core/parsers/gemini-parser.d.ts +10 -0
- package/dist/src/faf-core/parsers/gemini-parser.js +19 -77
- package/dist/src/faf-core/parsers/gemini-parser.js.map +1 -1
- package/dist/src/handlers/engine-adapter.d.ts +13 -12
- package/dist/src/handlers/engine-adapter.js +103 -682
- package/dist/src/handlers/engine-adapter.js.map +1 -1
- package/dist/src/handlers/resources.d.ts +19 -1
- package/dist/src/handlers/resources.js +108 -23
- package/dist/src/handlers/resources.js.map +1 -1
- package/dist/src/handlers/skills.d.ts +70 -0
- package/dist/src/handlers/skills.js +174 -0
- package/dist/src/handlers/skills.js.map +1 -0
- package/dist/src/handlers/tools.d.ts +41 -5
- package/dist/src/handlers/tools.js +213 -258
- package/dist/src/handlers/tools.js.map +1 -1
- package/dist/src/server.d.ts +4 -0
- package/dist/src/server.js +51 -6
- package/dist/src/server.js.map +1 -1
- package/dist/src/utils/faf-cli-bridge.d.ts +2 -0
- package/dist/src/utils/faf-cli-bridge.js +16 -0
- package/dist/src/utils/faf-cli-bridge.js.map +1 -1
- package/package.json +16 -13
- package/project.faf +11 -6
- package/scripts/check-engines.mjs +53 -0
- package/scripts/sync-version.js +33 -19
- package/skills/faf-ide/SKILL.md +40 -0
- package/dist/src/config/visibility.d.ts +0 -41
- package/dist/src/config/visibility.js +0 -158
- package/dist/src/config/visibility.js.map +0 -1
- package/dist/src/faf-core/commands/audit.d.ts +0 -21
- package/dist/src/faf-core/commands/audit.js +0 -83
- package/dist/src/faf-core/commands/audit.js.map +0 -1
- package/dist/src/faf-core/commands/auto.d.ts +0 -25
- package/dist/src/faf-core/commands/auto.js +0 -74
- package/dist/src/faf-core/commands/auto.js.map +0 -1
- package/dist/src/faf-core/commands/doctor.d.ts +0 -17
- package/dist/src/faf-core/commands/doctor.js +0 -198
- package/dist/src/faf-core/commands/doctor.js.map +0 -1
- package/dist/src/faf-core/commands/enhance.d.ts +0 -46
- package/dist/src/faf-core/commands/enhance.js +0 -360
- package/dist/src/faf-core/commands/enhance.js.map +0 -1
- package/dist/src/faf-core/commands/formats.d.ts +0 -22
- package/dist/src/faf-core/commands/formats.js +0 -117
- package/dist/src/faf-core/commands/formats.js.map +0 -1
- package/dist/src/faf-core/commands/human.d.ts +0 -27
- package/dist/src/faf-core/commands/human.js +0 -183
- package/dist/src/faf-core/commands/human.js.map +0 -1
- package/dist/src/faf-core/commands/init.d.ts +0 -26
- package/dist/src/faf-core/commands/init.js +0 -114
- package/dist/src/faf-core/commands/init.js.map +0 -1
- package/dist/src/faf-core/commands/innit.d.ts +0 -7
- package/dist/src/faf-core/commands/innit.js +0 -13
- package/dist/src/faf-core/commands/innit.js.map +0 -1
- package/dist/src/faf-core/commands/migrate.d.ts +0 -15
- package/dist/src/faf-core/commands/migrate.js +0 -86
- package/dist/src/faf-core/commands/migrate.js.map +0 -1
- package/dist/src/faf-core/commands/quick.d.ts +0 -16
- package/dist/src/faf-core/commands/quick.js +0 -184
- package/dist/src/faf-core/commands/quick.js.map +0 -1
- package/dist/src/faf-core/commands/readme.d.ts +0 -47
- package/dist/src/faf-core/commands/readme.js +0 -361
- package/dist/src/faf-core/commands/readme.js.map +0 -1
- package/dist/src/faf-core/commands/score.d.ts +0 -47
- package/dist/src/faf-core/commands/score.js +0 -49
- package/dist/src/faf-core/commands/score.js.map +0 -1
- package/dist/src/faf-core/commands/update.d.ts +0 -12
- package/dist/src/faf-core/commands/update.js +0 -46
- package/dist/src/faf-core/commands/update.js.map +0 -1
- package/dist/src/faf-core/commands/validate.d.ts +0 -21
- package/dist/src/faf-core/commands/validate.js +0 -81
- package/dist/src/faf-core/commands/validate.js.map +0 -1
- package/dist/src/faf-core/compiler/faf-compiler.d.ts +0 -138
- package/dist/src/faf-core/compiler/faf-compiler.js +0 -1362
- package/dist/src/faf-core/compiler/faf-compiler.js.map +0 -1
- package/dist/src/faf-core/engines/fab-formats-processor.d.ts +0 -166
- package/dist/src/faf-core/engines/fab-formats-processor.js +0 -1274
- package/dist/src/faf-core/engines/fab-formats-processor.js.map +0 -1
- package/dist/src/faf-core/engines/faf-dna.d.ts +0 -159
- package/dist/src/faf-core/engines/faf-dna.js +0 -555
- package/dist/src/faf-core/engines/faf-dna.js.map +0 -1
- package/dist/src/faf-core/engines/relentless-context-extractor.d.ts +0 -100
- package/dist/src/faf-core/engines/relentless-context-extractor.js +0 -625
- package/dist/src/faf-core/engines/relentless-context-extractor.js.map +0 -1
- package/dist/src/faf-core/fix-once/types.d.ts +0 -257
- package/dist/src/faf-core/fix-once/types.js +0 -26
- package/dist/src/faf-core/fix-once/types.js.map +0 -1
- package/dist/src/faf-core/generators/faf-generator-championship.d.ts +0 -16
- package/dist/src/faf-core/generators/faf-generator-championship.js +0 -463
- package/dist/src/faf-core/generators/faf-generator-championship.js.map +0 -1
- package/dist/src/faf-core/inject.d.ts +0 -19
- package/dist/src/faf-core/inject.js +0 -57
- package/dist/src/faf-core/inject.js.map +0 -1
- package/dist/src/faf-core/parsers/index.d.ts +0 -12
- package/dist/src/faf-core/parsers/index.js +0 -29
- package/dist/src/faf-core/parsers/index.js.map +0 -1
- package/dist/src/faf-core/utils/balance-visualizer.d.ts +0 -37
- package/dist/src/faf-core/utils/balance-visualizer.js +0 -197
- package/dist/src/faf-core/utils/balance-visualizer.js.map +0 -1
- package/dist/src/faf-core/utils/championship-style.d.ts +0 -109
- package/dist/src/faf-core/utils/championship-style.js +0 -219
- package/dist/src/faf-core/utils/championship-style.js.map +0 -1
- package/dist/src/faf-core/utils/chrome-extension-detector.d.ts +0 -73
- package/dist/src/faf-core/utils/chrome-extension-detector.js +0 -268
- package/dist/src/faf-core/utils/chrome-extension-detector.js.map +0 -1
- package/dist/src/faf-core/utils/platform-detector.d.ts +0 -30
- package/dist/src/faf-core/utils/platform-detector.js +0 -218
- package/dist/src/faf-core/utils/platform-detector.js.map +0 -1
- package/dist/src/faf-core/utils/technical-credit.d.ts +0 -35
- package/dist/src/faf-core/utils/technical-credit.js +0 -286
- package/dist/src/faf-core/utils/technical-credit.js.map +0 -1
- package/dist/src/faf-core/utils/yaml-generator.d.ts +0 -41
- package/dist/src/faf-core/utils/yaml-generator.js +0 -360
- package/dist/src/faf-core/utils/yaml-generator.js.map +0 -1
- package/dist/src/handlers/behavioral-instruction.d.ts +0 -16
- package/dist/src/handlers/behavioral-instruction.js +0 -43
- package/dist/src/handlers/behavioral-instruction.js.map +0 -1
- package/dist/src/handlers/championship-tools.d.ts +0 -116
- package/dist/src/handlers/championship-tools.js +0 -2320
- package/dist/src/handlers/championship-tools.js.map +0 -1
- package/dist/src/handlers/cloud-handler.d.ts +0 -59
- package/dist/src/handlers/cloud-handler.js +0 -348
- package/dist/src/handlers/cloud-handler.js.map +0 -1
- package/dist/src/handlers/tool-registry.d.ts +0 -23
- package/dist/src/handlers/tool-registry.js +0 -68
- package/dist/src/handlers/tool-registry.js.map +0 -1
- package/dist/src/handlers/tool-types.d.ts +0 -167
- package/dist/src/handlers/tool-types.js +0 -7
- package/dist/src/handlers/tool-types.js.map +0 -1
- package/dist/src/test-all-functions.d.ts +0 -15
- package/dist/src/test-all-functions.js +0 -163
- package/dist/src/test-all-functions.js.map +0 -1
- package/dist/src/types/mcp-tools.d.ts +0 -53
- package/dist/src/types/mcp-tools.js +0 -77
- package/dist/src/types/mcp-tools.js.map +0 -1
- package/dist/src/types/tool-visibility.d.ts +0 -36
- package/dist/src/types/tool-visibility.js +0 -551
- package/dist/src/types/tool-visibility.js.map +0 -1
- package/dist/src/utils/auto-path-detection.d.ts +0 -26
- package/dist/src/utils/auto-path-detection.js +0 -198
- package/dist/src/utils/auto-path-detection.js.map +0 -1
- package/dist/src/utils/championship-format.d.ts +0 -30
- package/dist/src/utils/championship-format.js +0 -81
- package/dist/src/utils/championship-format.js.map +0 -1
- package/dist/src/utils/cli-detector.d.ts +0 -17
- package/dist/src/utils/cli-detector.js +0 -247
- package/dist/src/utils/cli-detector.js.map +0 -1
- package/dist/src/utils/display-protocol.d.ts +0 -57
- package/dist/src/utils/display-protocol.js +0 -131
- package/dist/src/utils/display-protocol.js.map +0 -1
- package/dist/src/utils/username-detector.d.ts +0 -27
- package/dist/src/utils/username-detector.js +0 -90
- package/dist/src/utils/username-detector.js.map +0 -1
- package/dist/src/utils/visual-style.d.ts +0 -62
- package/dist/src/utils/visual-style.js +0 -166
- package/dist/src/utils/visual-style.js.map +0 -1
- package/scripts/postinstall.js +0 -50
- package/skill/SKILL.md +0 -385
|
@@ -1,2320 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* šļø Championship Tools Handler - F1-Inspired Grade Implementation
|
|
4
|
-
* Direct imports from FAF CLI - ZERO shell execution
|
|
5
|
-
* Sub-50ms response times - Championship performance
|
|
6
|
-
*
|
|
7
|
-
* IMPORTANT: Every response includes an AI-Readiness score footer.
|
|
8
|
-
* The user wants to achieve the highest score possible (100%).
|
|
9
|
-
* This score MUST always be shown in the footer - never hide it!
|
|
10
|
-
*/
|
|
11
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
-
if (k2 === undefined) k2 = k;
|
|
13
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
-
}
|
|
17
|
-
Object.defineProperty(o, k2, desc);
|
|
18
|
-
}) : (function(o, m, k, k2) {
|
|
19
|
-
if (k2 === undefined) k2 = k;
|
|
20
|
-
o[k2] = m[k];
|
|
21
|
-
}));
|
|
22
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
-
}) : function(o, v) {
|
|
25
|
-
o["default"] = v;
|
|
26
|
-
});
|
|
27
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
28
|
-
var ownKeys = function(o) {
|
|
29
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
30
|
-
var ar = [];
|
|
31
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
32
|
-
return ar;
|
|
33
|
-
};
|
|
34
|
-
return ownKeys(o);
|
|
35
|
-
};
|
|
36
|
-
return function (mod) {
|
|
37
|
-
if (mod && mod.__esModule) return mod;
|
|
38
|
-
var result = {};
|
|
39
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
40
|
-
__setModuleDefault(result, mod);
|
|
41
|
-
return result;
|
|
42
|
-
};
|
|
43
|
-
})();
|
|
44
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
-
exports.ChampionshipToolHandler = void 0;
|
|
46
|
-
const fs = __importStar(require("fs/promises"));
|
|
47
|
-
const path = __importStar(require("path"));
|
|
48
|
-
// ā
FIXED: Removed unused imports (formatScore, format3Lines, formatBigOrange, ChampionshipFormatter, AchievementStatus, wrapWithInstruction)
|
|
49
|
-
const engine_adapter_js_1 = require("./engine-adapter.js");
|
|
50
|
-
const display_protocol_js_1 = require("../utils/display-protocol.js");
|
|
51
|
-
const faf_file_finder_js_1 = require("../utils/faf-file-finder.js");
|
|
52
|
-
const inject_js_1 = require("../faf-core/inject.js");
|
|
53
|
-
const bi_sync_js_1 = require("../faf-core/commands/bi-sync.js");
|
|
54
|
-
const version_js_1 = require("../version.js");
|
|
55
|
-
const visibility_js_1 = require("../config/visibility.js");
|
|
56
|
-
const tool_registry_js_1 = require("./tool-registry.js");
|
|
57
|
-
const auto_path_detection_js_1 = require("../utils/auto-path-detection.js");
|
|
58
|
-
// Single source: faf-cli's real scorer + project.html renderer. handleDisplay
|
|
59
|
-
// MUST use these ā never reimplement scoring or HTML (kills divergence).
|
|
60
|
-
const faf_cli_1 = require("faf-cli");
|
|
61
|
-
// š FAF Score uses the 3-3-1 system: 3 lines, 3 words, 1 emoji!
|
|
62
|
-
// š„ Format-Finder (FF) integration for GAME-CHANGING stack detection!
|
|
63
|
-
// your MCP host filesystem context instruction
|
|
64
|
-
const FILESYSTEM_CONTEXT_INSTRUCTION = `
|
|
65
|
-
CRITICAL CONTEXT FOR CLAUDE DESKTOP:
|
|
66
|
-
- This MCP server executes on the USER'S REAL FILESYSTEM
|
|
67
|
-
- NOT in your MCP host's container (/home/claude)
|
|
68
|
-
- All paths are REAL system paths (/Users/username/ on macOS, /home/username/ on Linux, C:\\ on Windows)
|
|
69
|
-
- When discussing file locations, use the user's actual filesystem paths, not container paths
|
|
70
|
-
`;
|
|
71
|
-
class ChampionshipToolHandler {
|
|
72
|
-
startTime = 0;
|
|
73
|
-
fafEngine;
|
|
74
|
-
currentProjectDir = process.cwd();
|
|
75
|
-
contextWarningShown = false;
|
|
76
|
-
constructor(enginePath) {
|
|
77
|
-
this.fafEngine = new engine_adapter_js_1.FafEngineAdapter(enginePath || 'faf');
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* š Hybrid Context Establishment
|
|
81
|
-
* Detect missing .faf and warn user (don't auto-create)
|
|
82
|
-
* Shows REAL filesystem paths to establish ground truth
|
|
83
|
-
*/
|
|
84
|
-
async getContextWarningIfNeeded(directory) {
|
|
85
|
-
// Only show warning once per session
|
|
86
|
-
if (this.contextWarningShown)
|
|
87
|
-
return '';
|
|
88
|
-
const targetDir = directory || this.currentProjectDir;
|
|
89
|
-
// Check if .faf file exists
|
|
90
|
-
if (!await (0, faf_file_finder_js_1.hasFafFile)(targetDir)) {
|
|
91
|
-
this.contextWarningShown = true;
|
|
92
|
-
return `
|
|
93
|
-
ā ļø No project.faf found in ${targetDir}
|
|
94
|
-
|
|
95
|
-
For best results, create one:
|
|
96
|
-
- INSTALL: Say "Run faf_install_skill" (ā install faf-expert skill!)
|
|
97
|
-
- BEST: Invoke the faf-expert skill (ā 99/100 AI-readiness!)
|
|
98
|
-
- QUICK: Say "Run faf quick" (ā instant project.faf)
|
|
99
|
-
- PASTE: DROP/PASTE your README.md or package.json
|
|
100
|
-
|
|
101
|
-
Working on REAL filesystem: ${targetDir}
|
|
102
|
-
(Not in /home/claude container)
|
|
103
|
-
|
|
104
|
-
`;
|
|
105
|
-
}
|
|
106
|
-
return '';
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* š Calculate current FAF score for footer
|
|
110
|
-
* v1.2.0: Uses findFafFile() for project.faf support
|
|
111
|
-
*/
|
|
112
|
-
async calculateQuickScore(directory = this.currentProjectDir) {
|
|
113
|
-
let score = 0;
|
|
114
|
-
try {
|
|
115
|
-
if (await (0, faf_file_finder_js_1.hasFafFile)(directory))
|
|
116
|
-
score += 40;
|
|
117
|
-
if (await this.fileExists(path.join(directory, 'CLAUDE.md')))
|
|
118
|
-
score += 30;
|
|
119
|
-
if (await this.fileExists(path.join(directory, 'README.md')))
|
|
120
|
-
score += 15;
|
|
121
|
-
if (await this.fileExists(path.join(directory, 'package.json')))
|
|
122
|
-
score += 14;
|
|
123
|
-
}
|
|
124
|
-
catch {
|
|
125
|
-
// Silent fail for footer calculation
|
|
126
|
-
}
|
|
127
|
-
return score;
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* š„©ā”ļøš§” UNIVERSAL FOOTER - Shows on EVERY command!
|
|
131
|
-
* SINGLE SOURCE OF TRUTH: FAF Engine!
|
|
132
|
-
*/
|
|
133
|
-
async getUniversalFooter(directory) {
|
|
134
|
-
let score = 0;
|
|
135
|
-
const targetDir = directory || this.currentProjectDir || process.cwd();
|
|
136
|
-
// ā” ALWAYS use engine first for SINGLE SOURCE OF TRUTH!
|
|
137
|
-
try {
|
|
138
|
-
this.fafEngine.setWorkingDirectory(targetDir);
|
|
139
|
-
const result = await this.fafEngine.callEngine('score', ['--json']);
|
|
140
|
-
if (result.success && result.data) {
|
|
141
|
-
// Try to extract score from engine
|
|
142
|
-
if (typeof result.data.score === 'number') {
|
|
143
|
-
score = result.data.score;
|
|
144
|
-
}
|
|
145
|
-
else if (result.data.output) {
|
|
146
|
-
// Parse text output for score
|
|
147
|
-
const scoreMatch = result.data.output.match(/(\d+)%/);
|
|
148
|
-
if (scoreMatch) {
|
|
149
|
-
score = parseInt(scoreMatch[1]);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
catch {
|
|
155
|
-
// Silent fail - fallback to quick calc
|
|
156
|
-
}
|
|
157
|
-
// Only fallback if engine gave us nothing
|
|
158
|
-
if (score === 0) {
|
|
159
|
-
score = await this.calculateQuickScore(targetDir);
|
|
160
|
-
}
|
|
161
|
-
const percentage = Math.round((score / 100) * 100);
|
|
162
|
-
const trophy = percentage >= 90 ? ' š' : '';
|
|
163
|
-
// Make it BOLD with racing emojis - UNMISSABLE!
|
|
164
|
-
return `\nāāāāāāāāāāāāāāāāāāāāā\nšļø AI-READINESS: ${percentage}%${trophy} šļø\nāāāāāāāāāāāāāāāāāāāāā`;
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* šļø SHOW RAW FAF DATA IMMEDIATELY
|
|
168
|
-
* Championship Display Strategy: FORCE VISIBILITY!
|
|
169
|
-
*/
|
|
170
|
-
async formatResult(title, content, duration, directory) {
|
|
171
|
-
// š HYBRID CONTEXT: Check for missing .faf and warn (once per session)
|
|
172
|
-
const contextWarning = await this.getContextWarningIfNeeded(directory);
|
|
173
|
-
// Pass directory to footer so it calculates the right score!
|
|
174
|
-
const footer = await this.getUniversalFooter(directory);
|
|
175
|
-
// š CHAMPIONSHIP DISPLAY MODE - Using DisplayProtocol!
|
|
176
|
-
const fullOutput = `${contextWarning}${content}${footer}`;
|
|
177
|
-
// Return using DisplayProtocol's enhanced response format
|
|
178
|
-
// (No duplicate - DisplayProtocol.createResponse handles the display forcing)
|
|
179
|
-
return display_protocol_js_1.DisplayProtocol.createResponse(fullOutput, {
|
|
180
|
-
tool: title,
|
|
181
|
-
timestamp: new Date().toISOString(),
|
|
182
|
-
duration: duration
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
// ā
FIXED: Removed unused countProjectFiles method
|
|
186
|
-
/**
|
|
187
|
-
* List championship tools with visibility filtering
|
|
188
|
-
* v2.8.0: Supports core (20) vs advanced (31) tool filtering
|
|
189
|
-
*/
|
|
190
|
-
async listTools() {
|
|
191
|
-
// Get visibility configuration
|
|
192
|
-
const config = (0, visibility_js_1.getVisibilityConfig)();
|
|
193
|
-
const showAdvanced = config.showAdvanced;
|
|
194
|
-
// Define all tools
|
|
195
|
-
const allTools = [
|
|
196
|
-
// Core Tools - Priority 1
|
|
197
|
-
{
|
|
198
|
-
name: 'faf',
|
|
199
|
-
description: 'š .faf - Creates THE JPEG for AI! SPEEDY AI you can TRUST! š§”ā”ļø',
|
|
200
|
-
inputSchema: {
|
|
201
|
-
type: 'object',
|
|
202
|
-
properties: {
|
|
203
|
-
directory: { type: 'string', description: 'Project directory (defaults to current)' }
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
},
|
|
207
|
-
{
|
|
208
|
-
name: 'faf_display',
|
|
209
|
-
description: 'š¼ļø Render project.faf ā project.html (faf-cli\'s real scorer + renderer ā the same context your AI reads)',
|
|
210
|
-
inputSchema: {
|
|
211
|
-
type: 'object',
|
|
212
|
-
properties: {
|
|
213
|
-
directory: { type: 'string', description: 'Project directory (defaults to current)' },
|
|
214
|
-
output: { type: 'string', description: 'Output HTML file path' }
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
},
|
|
218
|
-
{
|
|
219
|
-
name: 'faf',
|
|
220
|
-
description: 'š§”ā”ļø FAF - Main command. IMPORTANT: Users provide LOCAL filesystem paths (e.g., /Users/username/projects/myapp). DO NOT use claude.ai containers (/mnt/user-data). Ask user for local path if needed. Uses real FAF file tools on local projects.',
|
|
221
|
-
inputSchema: {
|
|
222
|
-
type: 'object',
|
|
223
|
-
properties: {
|
|
224
|
-
directory: { type: 'string', description: 'LOCAL filesystem path to project directory (e.g., /Users/username/projects/myapp)' },
|
|
225
|
-
force: { type: 'boolean', description: 'Force overwrite existing files' }
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
},
|
|
229
|
-
{
|
|
230
|
-
name: 'faf_auto',
|
|
231
|
-
description: 'š ONE COMMAND SETUP - IMPORTANT: Users work on LOCAL projects. Ask for LOCAL filesystem path (e.g., /Users/username/projects/myapp). DO NOT use containers. Auto-scan, populate, score, sync using real FAF file tools.',
|
|
232
|
-
inputSchema: {
|
|
233
|
-
type: 'object',
|
|
234
|
-
properties: {
|
|
235
|
-
directory: { type: 'string', description: 'LOCAL filesystem path to project directory (e.g., /Users/username/projects/myapp)' }
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
},
|
|
239
|
-
{
|
|
240
|
-
name: 'faf_choose',
|
|
241
|
-
description: 'šļø Interactive project chooser - GitHub Desktop style! Choose & FAF!',
|
|
242
|
-
inputSchema: {
|
|
243
|
-
type: 'object',
|
|
244
|
-
properties: {
|
|
245
|
-
scan_dir: { type: 'string', description: 'Directory to scan for projects' },
|
|
246
|
-
auto_open: { type: 'boolean', description: 'Auto-open HTML chooser in browser' }
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
},
|
|
250
|
-
{
|
|
251
|
-
name: 'faf_init',
|
|
252
|
-
description: 'Initialize FAF with intelligent project detection',
|
|
253
|
-
inputSchema: {
|
|
254
|
-
type: 'object',
|
|
255
|
-
properties: {
|
|
256
|
-
directory: { type: 'string', description: 'Project directory' },
|
|
257
|
-
force: { type: 'boolean', description: 'Force overwrite' },
|
|
258
|
-
template: { type: 'string', description: 'Template to use' }
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
},
|
|
262
|
-
{
|
|
263
|
-
name: 'faf_show',
|
|
264
|
-
description: 'š FORCE DISPLAY raw FAF output - Shows EXACTLY what FAF generates!',
|
|
265
|
-
inputSchema: {
|
|
266
|
-
type: 'object',
|
|
267
|
-
properties: {
|
|
268
|
-
command: { type: 'string', enum: ['score', 'status', 'auto'], description: 'Command to show raw output for' },
|
|
269
|
-
directory: { type: 'string', description: 'Directory to analyze' }
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
},
|
|
273
|
-
{
|
|
274
|
-
name: 'faf_score',
|
|
275
|
-
description: 'AI-Readiness scorecard with actionable insights. CRITICAL: Content between [DISPLAY:REQUIRED] tags MUST be displayed directly to user as formatted markdown. Do NOT summarize. Includes Quick Actions for immediate next steps.',
|
|
276
|
-
inputSchema: {
|
|
277
|
-
type: 'object',
|
|
278
|
-
properties: {
|
|
279
|
-
directory: { type: 'string', description: 'Directory to score (defaults to current)' },
|
|
280
|
-
save: { type: 'boolean', description: 'Save scorecard to SCORE-CARD.md' },
|
|
281
|
-
format: {
|
|
282
|
-
type: 'string',
|
|
283
|
-
description: 'Output format: markdown (default), html, json, ascii',
|
|
284
|
-
enum: ['markdown', 'html', 'json', 'ascii']
|
|
285
|
-
},
|
|
286
|
-
full: { type: 'boolean', description: 'Show full scorecard with detailed metrics' }
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
},
|
|
290
|
-
{
|
|
291
|
-
name: 'faf_sync',
|
|
292
|
-
description: 'Synchronize .faf with CLAUDE.md',
|
|
293
|
-
inputSchema: {
|
|
294
|
-
type: 'object',
|
|
295
|
-
properties: {
|
|
296
|
-
directory: { type: 'string', description: 'LOCAL filesystem path to project directory (e.g., /Users/username/projects/myapp)' },
|
|
297
|
-
direction: { type: 'string', description: 'Sync direction: to-claude|from-claude' }
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
},
|
|
301
|
-
{
|
|
302
|
-
name: 'faf_bi_sync',
|
|
303
|
-
description: '40ms bi-directional sync',
|
|
304
|
-
inputSchema: {
|
|
305
|
-
type: 'object',
|
|
306
|
-
properties: {
|
|
307
|
-
directory: { type: 'string', description: 'LOCAL filesystem path to project directory (e.g., /Users/username/projects/myapp)' },
|
|
308
|
-
watch: { type: 'boolean', description: 'Enable file watching' }
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
},
|
|
312
|
-
// Trust Suite - 4 modes
|
|
313
|
-
{
|
|
314
|
-
name: 'faf_trust',
|
|
315
|
-
description: 'Trust validation with 4 modes',
|
|
316
|
-
inputSchema: {
|
|
317
|
-
type: 'object',
|
|
318
|
-
properties: {
|
|
319
|
-
mode: {
|
|
320
|
-
type: 'string',
|
|
321
|
-
enum: ['confidence', 'garage', 'panic', 'validated'],
|
|
322
|
-
description: 'Trust mode'
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
},
|
|
327
|
-
{
|
|
328
|
-
name: 'faf_trust_confidence',
|
|
329
|
-
description: 'Trust with confidence mode - steady state',
|
|
330
|
-
inputSchema: { type: 'object', properties: {} }
|
|
331
|
-
},
|
|
332
|
-
{
|
|
333
|
-
name: 'faf_trust_garage',
|
|
334
|
-
description: 'Trust garage mode - under the hood',
|
|
335
|
-
inputSchema: { type: 'object', properties: {} }
|
|
336
|
-
},
|
|
337
|
-
{
|
|
338
|
-
name: 'faf_trust_panic',
|
|
339
|
-
description: 'Trust panic mode - emergency validation',
|
|
340
|
-
inputSchema: { type: 'object', properties: {} }
|
|
341
|
-
},
|
|
342
|
-
{
|
|
343
|
-
name: 'faf_trust_validated',
|
|
344
|
-
description: 'Trust validated mode - production seal',
|
|
345
|
-
inputSchema: { type: 'object', properties: {} }
|
|
346
|
-
},
|
|
347
|
-
// Revolutionary Psychology Tools
|
|
348
|
-
{
|
|
349
|
-
name: 'faf_credit',
|
|
350
|
-
description: 'Technical Credit vs Technical Debt mindset',
|
|
351
|
-
inputSchema: {
|
|
352
|
-
type: 'object',
|
|
353
|
-
properties: {
|
|
354
|
-
award: { type: 'boolean', description: 'Award credit for good practices' }
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
},
|
|
358
|
-
{
|
|
359
|
-
name: 'faf_todo',
|
|
360
|
-
description: 'Gamified improvement tracking system',
|
|
361
|
-
inputSchema: {
|
|
362
|
-
type: 'object',
|
|
363
|
-
properties: {
|
|
364
|
-
add: { type: 'string', description: 'Add new todo' },
|
|
365
|
-
complete: { type: 'number', description: 'Complete todo by ID' }
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
},
|
|
369
|
-
{
|
|
370
|
-
name: 'faf_chat',
|
|
371
|
-
description: 'Natural language .faf generation',
|
|
372
|
-
inputSchema: {
|
|
373
|
-
type: 'object',
|
|
374
|
-
properties: {
|
|
375
|
-
prompt: { type: 'string', description: 'Your project description' }
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
},
|
|
379
|
-
{
|
|
380
|
-
name: 'faf_quick',
|
|
381
|
-
description: 'ā” Quick .faf creation - one-liner for instant context. Creates in ~/Projects/ (or ~/projects/ if exists).',
|
|
382
|
-
inputSchema: {
|
|
383
|
-
type: 'object',
|
|
384
|
-
properties: {
|
|
385
|
-
projectName: { type: 'string', description: 'Project name (creates ~/Projects/projectName/project.faf)' },
|
|
386
|
-
directory: { type: 'string', description: 'Full path to project directory (overrides projectName)' },
|
|
387
|
-
input: { type: 'string', description: 'Optional: Comma-separated project details' },
|
|
388
|
-
force: { type: 'boolean', description: 'Overwrite existing .faf file' }
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
},
|
|
392
|
-
{
|
|
393
|
-
name: 'faf_share',
|
|
394
|
-
description: 'Secure sharing with auto-sanitization',
|
|
395
|
-
inputSchema: {
|
|
396
|
-
type: 'object',
|
|
397
|
-
properties: {
|
|
398
|
-
sanitize: { type: 'boolean', description: 'Auto-sanitize secrets' }
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
},
|
|
402
|
-
// AI Enhancement Suite
|
|
403
|
-
{
|
|
404
|
-
name: 'faf_enhance',
|
|
405
|
-
description: 'AI enhancement - Claude-first, Big-3 compatible',
|
|
406
|
-
inputSchema: {
|
|
407
|
-
type: 'object',
|
|
408
|
-
properties: {
|
|
409
|
-
directory: { type: 'string', description: 'LOCAL filesystem path to project directory (e.g., /Users/username/projects/myapp)' },
|
|
410
|
-
model: { type: 'string', description: 'AI model to use' },
|
|
411
|
-
focus: { type: 'string', description: 'Enhancement focus area' }
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
},
|
|
415
|
-
{
|
|
416
|
-
name: 'faf_analyze',
|
|
417
|
-
description: 'Multi-model AI intelligence analysis',
|
|
418
|
-
inputSchema: {
|
|
419
|
-
type: 'object',
|
|
420
|
-
properties: {
|
|
421
|
-
models: { type: 'array', items: { type: 'string' } }
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
},
|
|
425
|
-
{
|
|
426
|
-
name: 'faf_verify',
|
|
427
|
-
description: 'Verify with Claude, ChatGPT, Gemini',
|
|
428
|
-
inputSchema: {
|
|
429
|
-
type: 'object',
|
|
430
|
-
properties: {
|
|
431
|
-
models: { type: 'array', items: { type: 'string' } }
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
},
|
|
435
|
-
// Human Context (6Ws Builder Integration)
|
|
436
|
-
{
|
|
437
|
-
name: 'faf_human_add',
|
|
438
|
-
description: 'š§” Add human_context to project.faf - Perfect for 6Ws Builder workflow (faf.one/6ws). Merge YAML from web form or set individual fields. Boosts AI-readiness score.',
|
|
439
|
-
inputSchema: {
|
|
440
|
-
type: 'object',
|
|
441
|
-
properties: {
|
|
442
|
-
yaml: {
|
|
443
|
-
type: 'string',
|
|
444
|
-
description: 'Complete human_context YAML from faf.one/6ws (copy-paste the entire human_context section)'
|
|
445
|
-
},
|
|
446
|
-
field: {
|
|
447
|
-
type: 'string',
|
|
448
|
-
description: 'Single field to set (who/what/where/why/when/how)'
|
|
449
|
-
},
|
|
450
|
-
value: {
|
|
451
|
-
type: 'string',
|
|
452
|
-
description: 'Value for the field'
|
|
453
|
-
},
|
|
454
|
-
directory: {
|
|
455
|
-
type: 'string',
|
|
456
|
-
description: 'LOCAL filesystem path to project directory (e.g., /Users/username/projects/myapp)'
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
},
|
|
461
|
-
{
|
|
462
|
-
name: 'faf_readme',
|
|
463
|
-
description: 'š Extract context from README.md - Instant AI-readiness boost! Automatically finds WHO/WHAT/WHERE/WHY/WHEN/HOW from existing README. Optionally merge into project.faf. Typical +25-35% score boost.',
|
|
464
|
-
inputSchema: {
|
|
465
|
-
type: 'object',
|
|
466
|
-
properties: {
|
|
467
|
-
merge: {
|
|
468
|
-
type: 'boolean',
|
|
469
|
-
description: 'Auto-merge extracted context into project.faf (default: false, just extract)'
|
|
470
|
-
},
|
|
471
|
-
overwrite: {
|
|
472
|
-
type: 'boolean',
|
|
473
|
-
description: 'Overwrite existing fields in project.faf (default: false, only fill empty fields)'
|
|
474
|
-
},
|
|
475
|
-
directory: {
|
|
476
|
-
type: 'string',
|
|
477
|
-
description: 'LOCAL filesystem path to project directory (e.g., /Users/username/projects/myapp)'
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
},
|
|
482
|
-
// Discovery & Navigation
|
|
483
|
-
{
|
|
484
|
-
name: 'faf_index',
|
|
485
|
-
description: 'A-Z reference catalog of your project',
|
|
486
|
-
inputSchema: {
|
|
487
|
-
type: 'object',
|
|
488
|
-
properties: {
|
|
489
|
-
directory: { type: 'string', description: 'LOCAL filesystem path to project directory (e.g., /Users/username/projects/myapp)' }
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
},
|
|
493
|
-
{
|
|
494
|
-
name: 'faf_search',
|
|
495
|
-
description: 'Search filesystem for files by name (TURBO-CAT powered). Solves the "dropped file path" problem - find where a file lives.',
|
|
496
|
-
inputSchema: {
|
|
497
|
-
type: 'object',
|
|
498
|
-
properties: {
|
|
499
|
-
query: { type: 'string', description: 'Filename to search for (e.g., "README.md")' },
|
|
500
|
-
type: { type: 'string', description: 'Search type: filename (default) | content | both' },
|
|
501
|
-
directory: { type: 'string', description: 'Directory to search (defaults to current directory)' }
|
|
502
|
-
},
|
|
503
|
-
required: ['query']
|
|
504
|
-
}
|
|
505
|
-
},
|
|
506
|
-
{
|
|
507
|
-
name: 'faf_stacks',
|
|
508
|
-
description: 'STACKTISTICS technology discovery',
|
|
509
|
-
inputSchema: {
|
|
510
|
-
type: 'object',
|
|
511
|
-
properties: {
|
|
512
|
-
directory: { type: 'string', description: 'LOCAL filesystem path to project directory (e.g., /Users/username/projects/myapp)' }
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
},
|
|
516
|
-
{
|
|
517
|
-
name: 'faf_faq',
|
|
518
|
-
description: 'Interactive help system',
|
|
519
|
-
inputSchema: {
|
|
520
|
-
type: 'object',
|
|
521
|
-
properties: {
|
|
522
|
-
topic: { type: 'string', description: 'Help topic' }
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
},
|
|
526
|
-
{
|
|
527
|
-
name: 'faf_guide',
|
|
528
|
-
description: 'FAF MCP usage guide for your MCP host - Projects convention, path resolution, and UX patterns',
|
|
529
|
-
inputSchema: {
|
|
530
|
-
type: 'object',
|
|
531
|
-
properties: {},
|
|
532
|
-
additionalProperties: false
|
|
533
|
-
}
|
|
534
|
-
},
|
|
535
|
-
// Developer Tools
|
|
536
|
-
{
|
|
537
|
-
name: 'faf_status',
|
|
538
|
-
description: 'Comprehensive project status with Mk3 Tier System',
|
|
539
|
-
inputSchema: {
|
|
540
|
-
type: 'object',
|
|
541
|
-
properties: {
|
|
542
|
-
directory: { type: 'string', description: 'Project directory (defaults to current)' }
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
},
|
|
546
|
-
{
|
|
547
|
-
name: 'faf_check',
|
|
548
|
-
description: 'Quick health check',
|
|
549
|
-
inputSchema: { type: 'object', properties: {} }
|
|
550
|
-
},
|
|
551
|
-
{
|
|
552
|
-
name: 'faf_clear',
|
|
553
|
-
description: 'Clear caches and state',
|
|
554
|
-
inputSchema: {
|
|
555
|
-
type: 'object',
|
|
556
|
-
properties: {
|
|
557
|
-
all: { type: 'boolean', description: 'Clear everything' },
|
|
558
|
-
cache: { type: 'boolean', description: 'Clear cache only' }
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
},
|
|
562
|
-
{
|
|
563
|
-
name: 'faf_edit',
|
|
564
|
-
description: 'Interactive editor with validation',
|
|
565
|
-
inputSchema: {
|
|
566
|
-
type: 'object',
|
|
567
|
-
properties: {
|
|
568
|
-
path: { type: 'string', description: 'File to edit' }
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
},
|
|
572
|
-
// Filesystem Operations - Native, no CLI needed!
|
|
573
|
-
{
|
|
574
|
-
name: 'faf_list',
|
|
575
|
-
description: 'List directory contents',
|
|
576
|
-
inputSchema: {
|
|
577
|
-
type: 'object',
|
|
578
|
-
properties: {
|
|
579
|
-
path: { type: 'string', description: 'Directory path' },
|
|
580
|
-
recursive: { type: 'boolean', description: 'List recursively' }
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
},
|
|
584
|
-
{
|
|
585
|
-
name: 'faf_exists',
|
|
586
|
-
description: 'Check if file or directory exists',
|
|
587
|
-
inputSchema: {
|
|
588
|
-
type: 'object',
|
|
589
|
-
properties: {
|
|
590
|
-
path: { type: 'string', description: 'Path to check' }
|
|
591
|
-
},
|
|
592
|
-
required: ['path']
|
|
593
|
-
}
|
|
594
|
-
},
|
|
595
|
-
{
|
|
596
|
-
name: 'faf_delete',
|
|
597
|
-
description: 'Delete files or directories',
|
|
598
|
-
inputSchema: {
|
|
599
|
-
type: 'object',
|
|
600
|
-
properties: {
|
|
601
|
-
path: { type: 'string', description: 'Path to delete' },
|
|
602
|
-
recursive: { type: 'boolean', description: 'Delete recursively' }
|
|
603
|
-
},
|
|
604
|
-
required: ['path']
|
|
605
|
-
}
|
|
606
|
-
},
|
|
607
|
-
{
|
|
608
|
-
name: 'faf_move',
|
|
609
|
-
description: 'Move or rename files',
|
|
610
|
-
inputSchema: {
|
|
611
|
-
type: 'object',
|
|
612
|
-
properties: {
|
|
613
|
-
from: { type: 'string', description: 'Source path' },
|
|
614
|
-
to: { type: 'string', description: 'Destination path' }
|
|
615
|
-
},
|
|
616
|
-
required: ['from', 'to']
|
|
617
|
-
}
|
|
618
|
-
},
|
|
619
|
-
{
|
|
620
|
-
name: 'faf_copy',
|
|
621
|
-
description: 'Copy files or directories',
|
|
622
|
-
inputSchema: {
|
|
623
|
-
type: 'object',
|
|
624
|
-
properties: {
|
|
625
|
-
from: { type: 'string', description: 'Source path' },
|
|
626
|
-
to: { type: 'string', description: 'Destination path' }
|
|
627
|
-
},
|
|
628
|
-
required: ['from', 'to']
|
|
629
|
-
}
|
|
630
|
-
},
|
|
631
|
-
{
|
|
632
|
-
name: 'faf_mkdir',
|
|
633
|
-
description: 'Create directories',
|
|
634
|
-
inputSchema: {
|
|
635
|
-
type: 'object',
|
|
636
|
-
properties: {
|
|
637
|
-
path: { type: 'string', description: 'Directory path' },
|
|
638
|
-
recursive: { type: 'boolean', description: 'Create parent directories' }
|
|
639
|
-
},
|
|
640
|
-
required: ['path']
|
|
641
|
-
}
|
|
642
|
-
},
|
|
643
|
-
// Keep the existing about tool
|
|
644
|
-
{
|
|
645
|
-
name: 'faf_about',
|
|
646
|
-
description: 'About FAF - stop FAFfing about!',
|
|
647
|
-
inputSchema: { type: 'object', properties: {} }
|
|
648
|
-
},
|
|
649
|
-
{
|
|
650
|
-
name: 'faf_version',
|
|
651
|
-
description: 'Show FAF version with MK2 engine and TURBO-CAT status',
|
|
652
|
-
inputSchema: { type: 'object', properties: {} }
|
|
653
|
-
},
|
|
654
|
-
{
|
|
655
|
-
name: 'faf_innit',
|
|
656
|
-
description: 'š¬š§ British version of init - same quality, more bruv!',
|
|
657
|
-
inputSchema: {
|
|
658
|
-
type: 'object',
|
|
659
|
-
properties: {
|
|
660
|
-
directory: { type: 'string', description: 'Target directory' },
|
|
661
|
-
force: { type: 'boolean', description: 'Overwrite existing .faf file' },
|
|
662
|
-
project_type: { type: 'string', description: 'Project template type' }
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
},
|
|
666
|
-
// NEW: 10 HIGH-PRIORITY CLIāMCP Continuity Tools
|
|
667
|
-
{
|
|
668
|
-
name: 'faf_formats',
|
|
669
|
-
description: 'š± TURBO-CAT format discovery (153 validated formats)',
|
|
670
|
-
inputSchema: {
|
|
671
|
-
type: 'object',
|
|
672
|
-
properties: {
|
|
673
|
-
directory: { type: 'string', description: 'Project directory to analyze' }
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
},
|
|
677
|
-
{
|
|
678
|
-
name: 'faf_validate',
|
|
679
|
-
description: 'Validate .faf file structure and completeness',
|
|
680
|
-
inputSchema: {
|
|
681
|
-
type: 'object',
|
|
682
|
-
properties: {
|
|
683
|
-
file: { type: 'string', description: 'Path to .faf file (auto-detects if not specified)' }
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
},
|
|
687
|
-
{
|
|
688
|
-
name: 'faf_doctor',
|
|
689
|
-
description: 'š„ Comprehensive health check for .faf and environment',
|
|
690
|
-
inputSchema: {
|
|
691
|
-
type: 'object',
|
|
692
|
-
properties: {
|
|
693
|
-
directory: { type: 'string', description: 'Project directory to check' }
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
},
|
|
697
|
-
{
|
|
698
|
-
name: 'faf_dna',
|
|
699
|
-
description: '𧬠Show Birth DNA and evolution tracking',
|
|
700
|
-
inputSchema: {
|
|
701
|
-
type: 'object',
|
|
702
|
-
properties: {
|
|
703
|
-
file: { type: 'string', description: 'Path to .faf file' }
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
},
|
|
707
|
-
{
|
|
708
|
-
name: 'faf_log',
|
|
709
|
-
description: 'š Show DNA evolution history and changes',
|
|
710
|
-
inputSchema: {
|
|
711
|
-
type: 'object',
|
|
712
|
-
properties: {
|
|
713
|
-
file: { type: 'string', description: 'Path to .faf file' },
|
|
714
|
-
limit: { type: 'number', description: 'Number of entries to show' }
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
},
|
|
718
|
-
{
|
|
719
|
-
name: 'faf_update',
|
|
720
|
-
description: 'š Update .faf file with latest project information',
|
|
721
|
-
inputSchema: {
|
|
722
|
-
type: 'object',
|
|
723
|
-
properties: {
|
|
724
|
-
file: { type: 'string', description: 'Path to .faf file' },
|
|
725
|
-
force: { type: 'boolean', description: 'Force update even if file is newer' }
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
},
|
|
729
|
-
{
|
|
730
|
-
name: 'faf_recover',
|
|
731
|
-
description: 'š Recover .faf from backups or DNA history',
|
|
732
|
-
inputSchema: {
|
|
733
|
-
type: 'object',
|
|
734
|
-
properties: {
|
|
735
|
-
file: { type: 'string', description: 'Path to .faf file to recover' },
|
|
736
|
-
timestamp: { type: 'string', description: 'Specific timestamp to recover from' }
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
},
|
|
740
|
-
{
|
|
741
|
-
name: 'faf_auth',
|
|
742
|
-
description: 'š Authenticate for Birth DNA tracking',
|
|
743
|
-
inputSchema: {
|
|
744
|
-
type: 'object',
|
|
745
|
-
properties: {
|
|
746
|
-
action: {
|
|
747
|
-
type: 'string',
|
|
748
|
-
enum: ['login', 'logout', 'status'],
|
|
749
|
-
description: 'Authentication action'
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
},
|
|
754
|
-
{
|
|
755
|
-
name: 'faf_audit',
|
|
756
|
-
description: 'š Comprehensive audit of .faf quality and completeness',
|
|
757
|
-
inputSchema: {
|
|
758
|
-
type: 'object',
|
|
759
|
-
properties: {
|
|
760
|
-
file: { type: 'string', description: 'Path to .faf file' },
|
|
761
|
-
detailed: { type: 'boolean', description: 'Show detailed audit report' }
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
},
|
|
765
|
-
{
|
|
766
|
-
name: 'faf_migrate',
|
|
767
|
-
description: 'š Migrate .faf to project.faf (format v2.5.0)',
|
|
768
|
-
inputSchema: {
|
|
769
|
-
type: 'object',
|
|
770
|
-
properties: {
|
|
771
|
-
directory: { type: 'string', description: 'Project directory containing .faf' },
|
|
772
|
-
backup: { type: 'boolean', description: 'Create backup of original .faf (default: true)' }
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
},
|
|
776
|
-
// Keep file operations
|
|
777
|
-
{
|
|
778
|
-
name: 'faf_read',
|
|
779
|
-
description: 'Read any file',
|
|
780
|
-
inputSchema: {
|
|
781
|
-
type: 'object',
|
|
782
|
-
properties: {
|
|
783
|
-
path: { type: 'string', description: 'File path' }
|
|
784
|
-
},
|
|
785
|
-
required: ['path']
|
|
786
|
-
}
|
|
787
|
-
},
|
|
788
|
-
{
|
|
789
|
-
name: 'faf_write',
|
|
790
|
-
description: 'Write any file',
|
|
791
|
-
inputSchema: {
|
|
792
|
-
type: 'object',
|
|
793
|
-
properties: {
|
|
794
|
-
path: { type: 'string', description: 'File path' },
|
|
795
|
-
content: { type: 'string', description: 'File content' }
|
|
796
|
-
},
|
|
797
|
-
required: ['path', 'content']
|
|
798
|
-
}
|
|
799
|
-
},
|
|
800
|
-
{
|
|
801
|
-
name: 'faf_skills',
|
|
802
|
-
description: 'šø List Claude Code skills from .faf file - See which skills are configured for this project',
|
|
803
|
-
inputSchema: {
|
|
804
|
-
type: 'object',
|
|
805
|
-
properties: {
|
|
806
|
-
directory: { type: 'string', description: 'Project directory (defaults to current)' }
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
},
|
|
810
|
-
{
|
|
811
|
-
name: 'faf_install_skill',
|
|
812
|
-
description: 'š Install faf-expert skill to Claude Code - Automatic installation of world-class FAF expertise',
|
|
813
|
-
inputSchema: {
|
|
814
|
-
type: 'object',
|
|
815
|
-
properties: {}
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
];
|
|
819
|
-
// Apply visibility filtering
|
|
820
|
-
const filteredTools = (0, tool_registry_js_1.filterTools)(allTools, showAdvanced);
|
|
821
|
-
return {
|
|
822
|
-
tools: filteredTools
|
|
823
|
-
};
|
|
824
|
-
}
|
|
825
|
-
/**
|
|
826
|
-
* Execute tool with sub-50ms performance target
|
|
827
|
-
*/
|
|
828
|
-
async callTool(name, _args) {
|
|
829
|
-
this.startTime = Date.now();
|
|
830
|
-
try {
|
|
831
|
-
// Route to appropriate handler - ZERO shell execution!
|
|
832
|
-
switch (name) {
|
|
833
|
-
// Core Tools
|
|
834
|
-
case 'faf':
|
|
835
|
-
case 'faf_auto':
|
|
836
|
-
return await this.handleAuto(_args);
|
|
837
|
-
case 'faf_choose':
|
|
838
|
-
return await this.handleChoose(_args);
|
|
839
|
-
case 'faf_display':
|
|
840
|
-
return await this.handleDisplay(_args);
|
|
841
|
-
case 'faf_init':
|
|
842
|
-
return await this.handleInit(_args);
|
|
843
|
-
case 'faf_show':
|
|
844
|
-
return await this.handleShow(_args);
|
|
845
|
-
case 'faf_score':
|
|
846
|
-
return await this.handleScore(_args);
|
|
847
|
-
case 'faf_sync':
|
|
848
|
-
return await this.handleSync(_args);
|
|
849
|
-
case 'faf_bi_sync':
|
|
850
|
-
return await this.handleBiSync(_args);
|
|
851
|
-
// Trust Suite
|
|
852
|
-
case 'faf_trust':
|
|
853
|
-
return await this.handleTrust(_args);
|
|
854
|
-
case 'faf_trust_confidence':
|
|
855
|
-
return await this.handleTrust({ mode: 'confidence' });
|
|
856
|
-
case 'faf_trust_garage':
|
|
857
|
-
return await this.handleTrust({ mode: 'garage' });
|
|
858
|
-
case 'faf_trust_panic':
|
|
859
|
-
return await this.handleTrust({ mode: 'panic' });
|
|
860
|
-
case 'faf_trust_validated':
|
|
861
|
-
return await this.handleTrust({ mode: 'validated' });
|
|
862
|
-
// Revolutionary Tools
|
|
863
|
-
case 'faf_credit':
|
|
864
|
-
return await this.handleCredit(_args);
|
|
865
|
-
case 'faf_todo':
|
|
866
|
-
return await this.handleTodo(_args);
|
|
867
|
-
case 'faf_chat':
|
|
868
|
-
return await this.handleChat(_args);
|
|
869
|
-
case 'faf_quick':
|
|
870
|
-
return await this.handleQuick(_args);
|
|
871
|
-
case 'faf_share':
|
|
872
|
-
return await this.handleShare(_args);
|
|
873
|
-
// AI Suite
|
|
874
|
-
case 'faf_enhance':
|
|
875
|
-
return await this.handleEnhance(_args);
|
|
876
|
-
case 'faf_analyze':
|
|
877
|
-
return await this.handleAnalyze(_args);
|
|
878
|
-
case 'faf_verify':
|
|
879
|
-
return await this.handleVerify(_args);
|
|
880
|
-
// Human Context (6Ws Builder integration)
|
|
881
|
-
case 'faf_human_add':
|
|
882
|
-
return await this.handleHumanAdd(_args);
|
|
883
|
-
case 'faf_readme':
|
|
884
|
-
return await this.handleReadme(_args);
|
|
885
|
-
// Discovery
|
|
886
|
-
case 'faf_index':
|
|
887
|
-
return await this.handleIndex(_args);
|
|
888
|
-
case 'faf_search':
|
|
889
|
-
return await this.handleSearch(_args);
|
|
890
|
-
case 'faf_stacks':
|
|
891
|
-
return await this.handleStacks(_args);
|
|
892
|
-
case 'faf_faq':
|
|
893
|
-
return await this.handleFaq(_args);
|
|
894
|
-
case 'faf_guide':
|
|
895
|
-
return await this.handleGuide(_args);
|
|
896
|
-
// Developer Tools
|
|
897
|
-
case 'faf_status':
|
|
898
|
-
return await this.handleStatus(_args);
|
|
899
|
-
case 'faf_check':
|
|
900
|
-
return await this.handleCheck(_args);
|
|
901
|
-
case 'faf_clear':
|
|
902
|
-
return await this.handleClear(_args);
|
|
903
|
-
case 'faf_edit':
|
|
904
|
-
return await this.handleEdit(_args);
|
|
905
|
-
// Filesystem Operations
|
|
906
|
-
case 'faf_list':
|
|
907
|
-
return await this.handleList(_args);
|
|
908
|
-
case 'faf_exists':
|
|
909
|
-
return await this.handleExists(_args);
|
|
910
|
-
case 'faf_delete':
|
|
911
|
-
return await this.handleDelete(_args);
|
|
912
|
-
case 'faf_move':
|
|
913
|
-
return await this.handleMove(_args);
|
|
914
|
-
case 'faf_copy':
|
|
915
|
-
return await this.handleCopy(_args);
|
|
916
|
-
case 'faf_mkdir':
|
|
917
|
-
return await this.handleMkdir(_args);
|
|
918
|
-
// About & File operations
|
|
919
|
-
case 'faf_about':
|
|
920
|
-
return await this.handleAbout(_args);
|
|
921
|
-
case 'faf_version':
|
|
922
|
-
return await this.handleVersion(_args);
|
|
923
|
-
case 'faf_innit':
|
|
924
|
-
return await this.handleInnit(_args);
|
|
925
|
-
// NEW: 10 HIGH-PRIORITY CLIāMCP Continuity Tools
|
|
926
|
-
case 'faf_formats':
|
|
927
|
-
return await this.handleFormats(_args);
|
|
928
|
-
case 'faf_validate':
|
|
929
|
-
return await this.handleValidate(_args);
|
|
930
|
-
case 'faf_doctor':
|
|
931
|
-
return await this.handleDoctor(_args);
|
|
932
|
-
case 'faf_dna':
|
|
933
|
-
return await this.handleDna(_args);
|
|
934
|
-
case 'faf_log':
|
|
935
|
-
return await this.handleLog(_args);
|
|
936
|
-
case 'faf_update':
|
|
937
|
-
return await this.handleUpdate(_args);
|
|
938
|
-
case 'faf_recover':
|
|
939
|
-
return await this.handleRecover(_args);
|
|
940
|
-
case 'faf_auth':
|
|
941
|
-
return await this.handleAuth(_args);
|
|
942
|
-
case 'faf_audit':
|
|
943
|
-
return await this.handleAudit(_args);
|
|
944
|
-
case 'faf_migrate':
|
|
945
|
-
return await this.handleMigrate(_args);
|
|
946
|
-
case 'faf_read':
|
|
947
|
-
return await this.handleRead(_args);
|
|
948
|
-
case 'faf_write':
|
|
949
|
-
return await this.handleWrite(_args);
|
|
950
|
-
case 'faf_skills':
|
|
951
|
-
return await this.handleSkills(_args);
|
|
952
|
-
case 'faf_install_skill':
|
|
953
|
-
return await this.handleInstallSkill(_args);
|
|
954
|
-
default:
|
|
955
|
-
throw new Error(`Unknown tool: ${name}`);
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
catch (error) {
|
|
959
|
-
const duration = Date.now() - this.startTime;
|
|
960
|
-
return {
|
|
961
|
-
content: [{
|
|
962
|
-
type: 'text',
|
|
963
|
-
text: `ā Error (${duration}ms): ${error.message}`
|
|
964
|
-
}],
|
|
965
|
-
isError: true
|
|
966
|
-
};
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
// Core Tool Handlers - Native implementations, no shell!
|
|
970
|
-
async handleAuto(args) {
|
|
971
|
-
try {
|
|
972
|
-
let dir = args?.directory || process.cwd();
|
|
973
|
-
// šÆ AUTO-PATH DETECTION: Extract project path from dropped files
|
|
974
|
-
if (dir && dir.startsWith('/mnt/user-data/uploads/')) {
|
|
975
|
-
const detection = (0, auto_path_detection_js_1.autoDetectPath)(dir);
|
|
976
|
-
if (detection.found && detection.path) {
|
|
977
|
-
dir = detection.path;
|
|
978
|
-
// Show success message
|
|
979
|
-
console.log(`ā
Auto-detected: "${detection.identifier}" ā ${dir}`);
|
|
980
|
-
}
|
|
981
|
-
else if (detection.error) {
|
|
982
|
-
return await this.formatResult('šÆ FAF Auto-Path Detection', `${detection.error}\n\n` +
|
|
983
|
-
`**What I tried:**\n` +
|
|
984
|
-
`⢠Extracted identifier: ${detection.identifier || 'none'}\n` +
|
|
985
|
-
`⢠Searched filesystem (case-insensitive)\n` +
|
|
986
|
-
`⢠No matching project directory found\n\n` +
|
|
987
|
-
`**What you can do:**\n` +
|
|
988
|
-
`⢠Provide the full path: \`faf_auto /full/path/to/project\`\n` +
|
|
989
|
-
`⢠Or navigate to the project and run: \`faf_quick\``);
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
// Smart Start - No directory provided = show DROP | PASTE | CREATE
|
|
993
|
-
if (!args?.directory || dir === '.' || dir === '/' || dir.length < 3) {
|
|
994
|
-
// Check if faf-expert skill is installed
|
|
995
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE || '/';
|
|
996
|
-
const skillPath = path.join(homeDir, '.claude', 'skills', 'faf-expert', 'SKILL.md');
|
|
997
|
-
const skillInstalled = await this.fileExists(skillPath);
|
|
998
|
-
const skillSection = skillInstalled
|
|
999
|
-
? `š **Expert Mode Ready!**\n` +
|
|
1000
|
-
`⢠faf-expert skill is installed ā
\n` +
|
|
1001
|
-
`⢠Invoke it anytime for 99/100 AI-readiness!\n\n`
|
|
1002
|
-
: `š **Want Expert Mode?**\n` +
|
|
1003
|
-
`⢠Install faf-expert skill: Say "Run faf_install_skill"\n` +
|
|
1004
|
-
`⢠Get 99/100 AI-readiness with world-class guidance!\n\n`;
|
|
1005
|
-
return await this.formatResult('š§”ā”ļø FAF - AI Context, On-Demand', `**DROP | PASTE | CREATE** - Click & Go!\n\n` +
|
|
1006
|
-
`šÆ **What is FAF?**\n` +
|
|
1007
|
-
`Persistent Project Context - makes your project AI-readable in <50ms\n\n` +
|
|
1008
|
-
`š **How to start:**\n` +
|
|
1009
|
-
`⢠**DROP** any file from your project (I'll find the root!)\n` +
|
|
1010
|
-
`⢠**PASTE** your project path: \`faf_auto /path/to/project\`\n` +
|
|
1011
|
-
`⢠**CREATE** instantly: Say "Run faf_quick"\n\n` +
|
|
1012
|
-
skillSection +
|
|
1013
|
-
`š” **Examples:**\n` +
|
|
1014
|
-
`\`faf_auto ~/Documents/my-app\`\n` +
|
|
1015
|
-
`\`faf_auto /Users/yourname/cool-project\`\n\n` +
|
|
1016
|
-
`š§”ā”ļø SPEEDY AI you can TRUST!`);
|
|
1017
|
-
}
|
|
1018
|
-
// Delegate to CLI - Single source of truth
|
|
1019
|
-
this.fafEngine.setWorkingDirectory(dir);
|
|
1020
|
-
const autoArgs = [];
|
|
1021
|
-
if (args.force)
|
|
1022
|
-
autoArgs.push('--force');
|
|
1023
|
-
const result = await this.fafEngine.callEngine('auto', autoArgs);
|
|
1024
|
-
if (!result.success) {
|
|
1025
|
-
return await this.formatResult('š FAF AUTO', `CLI Error: ${result.error}\n\nPlease ensure faf-cli v3.1.1+ is installed globally:\n npm install -g faf-cli\n or\n brew install faf-cli`);
|
|
1026
|
-
}
|
|
1027
|
-
return await this.formatResult('š FAF AUTO', result.data?.output || 'Success');
|
|
1028
|
-
}
|
|
1029
|
-
catch (error) {
|
|
1030
|
-
return await this.formatResult('ā FAF AUTO Failed', error.message);
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
async handleInit(args) {
|
|
1034
|
-
try {
|
|
1035
|
-
const dir = args.directory || process.cwd();
|
|
1036
|
-
// šØ your MCP host Protection: Detect root filesystem
|
|
1037
|
-
if (dir === '/' || dir === '') {
|
|
1038
|
-
const helpMessage = `šØ Directory Required!
|
|
1039
|
-
|
|
1040
|
-
your MCP host needs a target directory:
|
|
1041
|
-
|
|
1042
|
-
**Usage**:
|
|
1043
|
-
faf_init directory=/Users/wolfejam/my-project
|
|
1044
|
-
|
|
1045
|
-
**Example**:
|
|
1046
|
-
faf_init directory=/Users/wolfejam/GALLERY-SVELTE
|
|
1047
|
-
|
|
1048
|
-
š Can't determine working directory automatically in your MCP host.
|
|
1049
|
-
ā ļø Root filesystem (/) is read-only - specify your project path!`;
|
|
1050
|
-
return await this.formatResult('š FAF Init', helpMessage);
|
|
1051
|
-
}
|
|
1052
|
-
// ā” USE THE FAF ENGINE!
|
|
1053
|
-
this.fafEngine.setWorkingDirectory(dir);
|
|
1054
|
-
const initArgs = [];
|
|
1055
|
-
if (args.force)
|
|
1056
|
-
initArgs.push('--force');
|
|
1057
|
-
if (args.project_type) {
|
|
1058
|
-
initArgs.push('--project-type');
|
|
1059
|
-
initArgs.push(args.project_type);
|
|
1060
|
-
}
|
|
1061
|
-
const result = await this.fafEngine.callEngine('init', initArgs);
|
|
1062
|
-
if (!result.success) {
|
|
1063
|
-
return await this.formatResult('š FAF Init', `CLI Error: ${result.error}\n\nPlease ensure faf-cli v3.1.1+ is installed globally:\n npm install -g faf-cli\n or\n brew install faf-cli`);
|
|
1064
|
-
}
|
|
1065
|
-
return await this.formatResult('š FAF Init', result.data?.output || 'Success');
|
|
1066
|
-
}
|
|
1067
|
-
catch (error) {
|
|
1068
|
-
return await this.formatResult('š FAF Init', `Error: ${error.message}`);
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
async fileExists(filePath) {
|
|
1072
|
-
try {
|
|
1073
|
-
await fs.access(filePath);
|
|
1074
|
-
return true;
|
|
1075
|
-
}
|
|
1076
|
-
catch {
|
|
1077
|
-
return false;
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
|
-
async handleDisplay(args) {
|
|
1081
|
-
// Single-sourced render of project.faf ā HTML. Same pipeline as
|
|
1082
|
-
// faf-cli's `faf show` / `faf export --html`: the real scorer + the
|
|
1083
|
-
// canonical project.html renderer. No reimplementation, no fake
|
|
1084
|
-
// file-presence score, no divergent template.
|
|
1085
|
-
const targetDir = args?.directory || process.cwd();
|
|
1086
|
-
const fafPath = (0, faf_cli_1.findFafFile)(targetDir);
|
|
1087
|
-
if (!fafPath) {
|
|
1088
|
-
return await this.formatResult('š¼ļø FAF Display', `No .faf found in ${targetDir}\n\n` +
|
|
1089
|
-
`Run faf_init to create one, then faf_display to render it.`);
|
|
1090
|
-
}
|
|
1091
|
-
const data = (0, faf_cli_1.readFaf)(fafPath);
|
|
1092
|
-
const result = (0, faf_cli_1.scoreFafYaml)((0, faf_cli_1.readFafRaw)(fafPath));
|
|
1093
|
-
const html = (0, faf_cli_1.generateProjectHtml)(data, result, fafPath);
|
|
1094
|
-
const outputPath = args?.output || path.join(targetDir, 'project.html');
|
|
1095
|
-
await fs.writeFile(outputPath, html);
|
|
1096
|
-
return await this.formatResult('š¼ļø FAF Display Generated', `Rendered project.faf ā ${outputPath}\n\n` +
|
|
1097
|
-
`Single-sourced from faf-cli ā the real scorer and renderer, ` +
|
|
1098
|
-
`the same truth your AI reads.\n` +
|
|
1099
|
-
`file://${outputPath}`);
|
|
1100
|
-
}
|
|
1101
|
-
async handleShow(args) {
|
|
1102
|
-
// š«š CHOCOLATE ORANGE - NO WRAPPERS!
|
|
1103
|
-
const command = args.command || 'score';
|
|
1104
|
-
const directory = args.directory || process.cwd();
|
|
1105
|
-
if (command === 'score') {
|
|
1106
|
-
const targetDir = directory;
|
|
1107
|
-
const s = this.getFafScore(targetDir);
|
|
1108
|
-
if (!s.found) {
|
|
1109
|
-
return display_protocol_js_1.DisplayProtocol.createResponse(`# FAF Score Card\n\n` +
|
|
1110
|
-
`No \`.faf\` found in \`${targetDir}\`.\n\n` +
|
|
1111
|
-
`Run \`faf_init\` to create one ā then \`faf_show\` renders the real score.`, { tool: 'faf_show', command });
|
|
1112
|
-
}
|
|
1113
|
-
const barWidth = 24;
|
|
1114
|
-
const filled = Math.round((s.score / 100) * barWidth);
|
|
1115
|
-
const progressBar = 'ā'.repeat(filled) + 'ā'.repeat(barWidth - filled);
|
|
1116
|
-
const output = `# FAF Score Card
|
|
1117
|
-
|
|
1118
|
-
## **${s.score}/100** ${s.tierDisplay}
|
|
1119
|
-
|
|
1120
|
-
${progressBar} ${s.score}%
|
|
1121
|
-
|
|
1122
|
-
${s.populated}/${s.total} slots populated${s.nextTier ? ` Ā· next: ${s.nextTier}` : ' Ā· top tier'}
|
|
1123
|
-
|
|
1124
|
-
---
|
|
1125
|
-
|
|
1126
|
-
> Scored by faf-cli's real scorer ā the same context your AI reads.
|
|
1127
|
-
> For slot-by-slot detail run \`faf score\` (faf-cli).
|
|
1128
|
-
|
|
1129
|
-
**AI-Readiness: ${s.score}%**`;
|
|
1130
|
-
return display_protocol_js_1.DisplayProtocol.createResponse(output, {
|
|
1131
|
-
tool: 'faf_show',
|
|
1132
|
-
command,
|
|
1133
|
-
});
|
|
1134
|
-
}
|
|
1135
|
-
// Default fallback - also use DisplayProtocol
|
|
1136
|
-
return display_protocol_js_1.DisplayProtocol.createResponse('Command not recognized. Try: faf_show --command score', { tool: 'faf_show', isError: true });
|
|
1137
|
-
}
|
|
1138
|
-
async handleScore(args) {
|
|
1139
|
-
const targetDir = args?.directory || process.cwd();
|
|
1140
|
-
const saveCard = args?.save === true;
|
|
1141
|
-
const format = args?.format || 'markdown';
|
|
1142
|
-
// HTML delegates to the single-sourced renderer (faf-cli's project.html).
|
|
1143
|
-
if (format === 'html') {
|
|
1144
|
-
return await this.handleDisplay({ directory: targetDir, output: path.join(targetDir, 'SCORE-CARD.html') });
|
|
1145
|
-
}
|
|
1146
|
-
const sc = this.getFafScore(targetDir);
|
|
1147
|
-
if (!sc.found) {
|
|
1148
|
-
return await this.formatResult('šļø FAF Score', `No \`.faf\` found in \`${targetDir}\`.\n\nRun \`faf_init\` to create one.`, undefined, targetDir);
|
|
1149
|
-
}
|
|
1150
|
-
const barWidth = 24;
|
|
1151
|
-
const filled = Math.round((sc.score / 100) * barWidth);
|
|
1152
|
-
const progressBar = 'ā'.repeat(filled) + 'ā'.repeat(barWidth - filled);
|
|
1153
|
-
let result = '';
|
|
1154
|
-
if (format === 'json') {
|
|
1155
|
-
result = JSON.stringify({
|
|
1156
|
-
project: path.basename(targetDir),
|
|
1157
|
-
score: sc.score,
|
|
1158
|
-
tier: sc.tierName,
|
|
1159
|
-
slots: { populated: sc.populated, total: sc.total },
|
|
1160
|
-
next_tier: sc.nextTier,
|
|
1161
|
-
source: 'faf-cli',
|
|
1162
|
-
version: version_js_1.VERSION,
|
|
1163
|
-
}, null, 2);
|
|
1164
|
-
}
|
|
1165
|
-
else if (format === 'ascii') {
|
|
1166
|
-
result =
|
|
1167
|
-
`FAF Score: ${sc.score}/100 ${sc.tierDisplay}\n` +
|
|
1168
|
-
`${progressBar} ${sc.score}%\n` +
|
|
1169
|
-
`${sc.populated}/${sc.total} slots${sc.nextTier ? ` next: ${sc.nextTier}` : ' top tier'}`;
|
|
1170
|
-
}
|
|
1171
|
-
else {
|
|
1172
|
-
// markdown (default). `full` adds nothing fabricated ā the real
|
|
1173
|
-
// score IS the full truth; the old championship theater is dead.
|
|
1174
|
-
result =
|
|
1175
|
-
`# FAF Score Card\n\n` +
|
|
1176
|
-
`## **${sc.score}/100** ${sc.tierDisplay}\n\n` +
|
|
1177
|
-
`${progressBar} ${sc.score}%\n\n` +
|
|
1178
|
-
`**${sc.populated}/${sc.total} slots populated**${sc.nextTier ? ` Ā· next: ${sc.nextTier}` : ' Ā· top tier'}\n\n` +
|
|
1179
|
-
`---\n\n` +
|
|
1180
|
-
`> Scored by faf-cli's real scorer ā the same context your AI reads.\n` +
|
|
1181
|
-
`> Slot-by-slot detail: \`faf score\` (faf-cli).`;
|
|
1182
|
-
}
|
|
1183
|
-
if (saveCard && format !== 'json') {
|
|
1184
|
-
const scoreCardPath = path.join(targetDir, 'SCORE-CARD.md');
|
|
1185
|
-
await fs.writeFile(scoreCardPath, result);
|
|
1186
|
-
result += `\n\nā
**Score card saved to:** \`${scoreCardPath}\``;
|
|
1187
|
-
}
|
|
1188
|
-
return await this.formatResult('šļø FAF Score', result, undefined, targetDir);
|
|
1189
|
-
}
|
|
1190
|
-
async handleSync(args) {
|
|
1191
|
-
const cwd = process.cwd();
|
|
1192
|
-
// ā” USE THE FAF ENGINE!
|
|
1193
|
-
try {
|
|
1194
|
-
this.fafEngine.setWorkingDirectory(cwd);
|
|
1195
|
-
const syncArgs = [];
|
|
1196
|
-
if (args.direction === 'from-claude') {
|
|
1197
|
-
syncArgs.push('--from-claude');
|
|
1198
|
-
}
|
|
1199
|
-
const result = await this.fafEngine.callEngine('sync', syncArgs);
|
|
1200
|
-
if (result.success) {
|
|
1201
|
-
const output = result.data?.output || 'Files synchronized';
|
|
1202
|
-
return await this.formatResult('š FAF Sync', output);
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
|
-
catch (engineError) {
|
|
1206
|
-
console.warn('FAF Engine sync failed, using native:', engineError);
|
|
1207
|
-
}
|
|
1208
|
-
// Fallback to native implementation
|
|
1209
|
-
const direction = args.direction || 'to-claude';
|
|
1210
|
-
if (direction === 'to-claude') {
|
|
1211
|
-
// Read from any existing FAF file (project.faf, *.faf, or .faf)
|
|
1212
|
-
const fafResult = await (0, faf_file_finder_js_1.findFafFile)(cwd);
|
|
1213
|
-
if (!fafResult) {
|
|
1214
|
-
return await this.formatResult('š FAF Sync', 'No FAF file found to sync from');
|
|
1215
|
-
}
|
|
1216
|
-
const fafContent = await fs.readFile(fafResult.path, 'utf-8');
|
|
1217
|
-
await (0, inject_js_1.injectFafBlock)(path.join(cwd, 'CLAUDE.md'), fafContent + `\n\n# Synced from ${fafResult.filename}`);
|
|
1218
|
-
return await this.formatResult('š FAF Sync', `Synced ${fafResult.filename} ā CLAUDE.md (native fallback)`);
|
|
1219
|
-
}
|
|
1220
|
-
else {
|
|
1221
|
-
// Write to project.faf (new standard)
|
|
1222
|
-
const claudeContent = await fs.readFile(path.join(cwd, 'CLAUDE.md'), 'utf-8');
|
|
1223
|
-
const fafPath = (0, faf_file_finder_js_1.getNewFafFilePath)(cwd);
|
|
1224
|
-
await fs.writeFile(fafPath, claudeContent);
|
|
1225
|
-
return await this.formatResult('š FAF Sync', 'Synced CLAUDE.md ā project.faf (native fallback)');
|
|
1226
|
-
}
|
|
1227
|
-
}
|
|
1228
|
-
async handleBiSync(args) {
|
|
1229
|
-
const startSync = Date.now();
|
|
1230
|
-
const cwd = process.cwd();
|
|
1231
|
-
// ā” USE THE FAF ENGINE!
|
|
1232
|
-
try {
|
|
1233
|
-
this.fafEngine.setWorkingDirectory(cwd);
|
|
1234
|
-
const biSyncArgs = [];
|
|
1235
|
-
if (args.force)
|
|
1236
|
-
biSyncArgs.push('--force');
|
|
1237
|
-
const result = await this.fafEngine.callEngine('bi-sync', biSyncArgs);
|
|
1238
|
-
if (result.success) {
|
|
1239
|
-
const syncTime = Date.now() - startSync;
|
|
1240
|
-
const output = result.data?.output || `Bi-directional sync complete in ${syncTime}ms`;
|
|
1241
|
-
return await this.formatResult('š FAF Bi-Sync', output + (syncTime < 40 ? ' šļø' : ''));
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
catch (engineError) {
|
|
1245
|
-
console.warn('FAF Engine bi-sync failed, using native:', engineError);
|
|
1246
|
-
}
|
|
1247
|
-
// Native fallback: sync project.faf ā CLAUDE.md, non-destructively.
|
|
1248
|
-
// .faf is canonical ā never overwrite it (the old merge corrupted it by
|
|
1249
|
-
// concatenating CLAUDE.md back into project.faf). Inject the faf-derived
|
|
1250
|
-
// block into CLAUDE.md and preserve everything the user wrote.
|
|
1251
|
-
const fafResult = await (0, faf_file_finder_js_1.findFafFile)(cwd);
|
|
1252
|
-
if (fafResult) {
|
|
1253
|
-
const fafContent = await fs.readFile(fafResult.path, 'utf-8').catch(() => '');
|
|
1254
|
-
await (0, inject_js_1.injectFafBlock)(path.join(cwd, 'CLAUDE.md'), (0, bi_sync_js_1.fafToClaudeMd)(fafContent));
|
|
1255
|
-
}
|
|
1256
|
-
const syncTime = Date.now() - startSync;
|
|
1257
|
-
return await this.formatResult('š FAF Bi-Sync', `Synced in ${syncTime}ms (native) ${syncTime < 40 ? 'šļø' : ''}`);
|
|
1258
|
-
}
|
|
1259
|
-
async handleTrust(args) {
|
|
1260
|
-
const mode = (args.mode || 'confidence');
|
|
1261
|
-
const messages = {
|
|
1262
|
-
confidence: 'ā
High confidence - Ready for production',
|
|
1263
|
-
garage: 'š§ Under the hood - Everything looks good',
|
|
1264
|
-
panic: 'šØ PANIC MODE - But we got this!',
|
|
1265
|
-
validated: 'š Championship validated - 100% trusted'
|
|
1266
|
-
};
|
|
1267
|
-
return await this.formatResult(`š FAF Trust (${mode})`, messages[mode]);
|
|
1268
|
-
}
|
|
1269
|
-
// Revolutionary Tool Handlers
|
|
1270
|
-
async handleCredit(args) {
|
|
1271
|
-
const credit = args.award ? 'š Technical Credit awarded!' : 'š Current credit: 100 points';
|
|
1272
|
-
return await this.formatResult('š FAF Credit', credit);
|
|
1273
|
-
}
|
|
1274
|
-
async handleTodo(args) {
|
|
1275
|
-
if (args.add) {
|
|
1276
|
-
return await this.formatResult('š FAF Todo', `Added: ${args.add}`);
|
|
1277
|
-
}
|
|
1278
|
-
else if (args.complete) {
|
|
1279
|
-
return await this.formatResult('š FAF Todo', `Completed todo #${args.complete}`);
|
|
1280
|
-
}
|
|
1281
|
-
return await this.formatResult('š FAF Todo', 'No todos yet. Living the dream!');
|
|
1282
|
-
}
|
|
1283
|
-
async handleChat(args) {
|
|
1284
|
-
const prompt = args.prompt || 'Tell me about your project';
|
|
1285
|
-
const fafContent = `# Generated by FAF Chat\nproject: ${prompt}\ncontext: AI-generated\nversion: 1.0.0`;
|
|
1286
|
-
return await this.formatResult('š¬ FAF Chat', fafContent);
|
|
1287
|
-
}
|
|
1288
|
-
async handleQuick(args) {
|
|
1289
|
-
const startTime = Date.now();
|
|
1290
|
-
try {
|
|
1291
|
-
// No directory provided = prompt for project name
|
|
1292
|
-
if (!args?.directory && !args?.projectName) {
|
|
1293
|
-
const duration = Date.now() - startTime;
|
|
1294
|
-
return await this.formatResult('ā” FAF Quick - Create New Project', `**Enter a name for your project**\n\n` +
|
|
1295
|
-
`I'll create: \`~/Projects/your-project-name/project.faf\`\n` +
|
|
1296
|
-
`(or \`~/projects/\` if that folder exists)\n\n` +
|
|
1297
|
-
`š” **Quick create:**\n` +
|
|
1298
|
-
`\`faf_quick { projectName: "my-cool-app" }\`\n\n` +
|
|
1299
|
-
`**Custom location:**\n` +
|
|
1300
|
-
`\`faf_quick { directory: "/custom/path/to/project" }\`\n\n` +
|
|
1301
|
-
`**With details:**\n` +
|
|
1302
|
-
`\`faf_quick { projectName: "MyApp", input: "Next.js e-commerce, TypeScript" }\`\n\n` +
|
|
1303
|
-
`šÆ Projects-based: We organize your work in a Projects folder`, duration);
|
|
1304
|
-
}
|
|
1305
|
-
// Determine directory: explicit path OR projectName in Projects folder
|
|
1306
|
-
let dir;
|
|
1307
|
-
if (args.directory) {
|
|
1308
|
-
dir = args.directory;
|
|
1309
|
-
}
|
|
1310
|
-
else if (args.projectName) {
|
|
1311
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE || '~';
|
|
1312
|
-
// Smart Projects folder detection
|
|
1313
|
-
// Priority: ~/projects/ (lowercase) > ~/Projects/ (capitalized) > create ~/Projects/
|
|
1314
|
-
let projectsDir;
|
|
1315
|
-
const projectsLower = path.join(homeDir, 'projects');
|
|
1316
|
-
const projectsUpper = path.join(homeDir, 'Projects');
|
|
1317
|
-
if (await this.fileExists(projectsLower)) {
|
|
1318
|
-
projectsDir = projectsLower;
|
|
1319
|
-
}
|
|
1320
|
-
else if (await this.fileExists(projectsUpper)) {
|
|
1321
|
-
projectsDir = projectsUpper;
|
|
1322
|
-
}
|
|
1323
|
-
else {
|
|
1324
|
-
projectsDir = projectsUpper; // Default to capitalized if creating new
|
|
1325
|
-
}
|
|
1326
|
-
dir = path.join(projectsDir, args.projectName);
|
|
1327
|
-
}
|
|
1328
|
-
else {
|
|
1329
|
-
throw new Error('Either directory or projectName is required');
|
|
1330
|
-
}
|
|
1331
|
-
// Create the project directory (and parent if needed)
|
|
1332
|
-
await fs.mkdir(dir, { recursive: true });
|
|
1333
|
-
// Call faf-cli quick command
|
|
1334
|
-
this.fafEngine.setWorkingDirectory(dir);
|
|
1335
|
-
const quickArgs = [];
|
|
1336
|
-
if (args.input) {
|
|
1337
|
-
quickArgs.push(args.input);
|
|
1338
|
-
}
|
|
1339
|
-
if (args.force) {
|
|
1340
|
-
quickArgs.push('--force');
|
|
1341
|
-
}
|
|
1342
|
-
const result = await this.fafEngine.callEngine('quick', quickArgs);
|
|
1343
|
-
const duration = Date.now() - startTime;
|
|
1344
|
-
if (result.success && result.data?.output) {
|
|
1345
|
-
return await this.formatResult('ā” FAF Quick', result.data.output, duration, dir);
|
|
1346
|
-
}
|
|
1347
|
-
else {
|
|
1348
|
-
return await this.formatResult('ā” FAF Quick', result.data?.error || 'Quick creation failed', duration, dir);
|
|
1349
|
-
}
|
|
1350
|
-
}
|
|
1351
|
-
catch (error) {
|
|
1352
|
-
const duration = Date.now() - startTime;
|
|
1353
|
-
return await this.formatResult('ā” FAF Quick', `Error: ${error.message}`, duration);
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
/**
|
|
1357
|
-
* š§” Handle human_context add/merge
|
|
1358
|
-
* For 6Ws Builder workflow: user fills faf.one/6ws, pastes YAML here
|
|
1359
|
-
*/
|
|
1360
|
-
async handleHumanAdd(args) {
|
|
1361
|
-
const startTime = Date.now();
|
|
1362
|
-
try {
|
|
1363
|
-
const dir = args.directory || this.currentProjectDir;
|
|
1364
|
-
// Validate input
|
|
1365
|
-
if (!args.yaml && (!args.field || !args.value)) {
|
|
1366
|
-
return await this.formatResult('š§” Human Context', `**Usage:**\n\n` +
|
|
1367
|
-
`**From 6Ws Builder (faf.one/6ws):**\n` +
|
|
1368
|
-
`1. Visit https://faf.one/6ws\n` +
|
|
1369
|
-
`2. Fill out the 6 questions\n` +
|
|
1370
|
-
`3. Copy the human_context YAML\n` +
|
|
1371
|
-
`4. Use: \`faf_human_add { yaml: "paste here" }\`\n\n` +
|
|
1372
|
-
`**Single field:**\n` +
|
|
1373
|
-
`\`faf_human_add { field: "who", value: "developers" }\`\n\n` +
|
|
1374
|
-
`**Valid fields:** who, what, where, why, when, how`, Date.now() - startTime, dir);
|
|
1375
|
-
}
|
|
1376
|
-
// Prepare engine args
|
|
1377
|
-
const engineArgs = [dir];
|
|
1378
|
-
if (args.yaml) {
|
|
1379
|
-
engineArgs.push(`--yaml=${args.yaml}`);
|
|
1380
|
-
}
|
|
1381
|
-
if (args.field) {
|
|
1382
|
-
engineArgs.push(`--field=${args.field}`);
|
|
1383
|
-
}
|
|
1384
|
-
if (args.value) {
|
|
1385
|
-
engineArgs.push(`--value=${args.value}`);
|
|
1386
|
-
}
|
|
1387
|
-
// Call bundled human command
|
|
1388
|
-
this.fafEngine.setWorkingDirectory(dir);
|
|
1389
|
-
const result = await this.fafEngine.callEngine('human-add', engineArgs);
|
|
1390
|
-
const duration = Date.now() - startTime;
|
|
1391
|
-
if (result.success && result.data) {
|
|
1392
|
-
const fieldsUpdated = result.data.fieldsUpdated || [];
|
|
1393
|
-
const fieldsList = fieldsUpdated.join(', ');
|
|
1394
|
-
return await this.formatResult('š§” Human Context Added', `${result.data.message}\n\n` +
|
|
1395
|
-
`**Updated fields:** ${fieldsList}\n\n` +
|
|
1396
|
-
`**Next steps:**\n` +
|
|
1397
|
-
`1. Run \`faf_score\` to see your new AI-readiness score\n` +
|
|
1398
|
-
`2. Your context is now available to all AI assistants\n\n` +
|
|
1399
|
-
`š” **Tip:** Complete all 6 Ws (who, what, where, why, when, how) for maximum score boost!`, duration, dir);
|
|
1400
|
-
}
|
|
1401
|
-
else {
|
|
1402
|
-
return await this.formatResult('š§” Human Context', result.error || 'Failed to add human context', duration, dir);
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
catch (error) {
|
|
1406
|
-
const duration = Date.now() - startTime;
|
|
1407
|
-
return await this.formatResult('š§” Human Context', `Error: ${error.message}`, duration);
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
/**
|
|
1411
|
-
* š Handle README context extraction
|
|
1412
|
-
* Extract 6 Ws from existing README.md and optionally merge into project.faf
|
|
1413
|
-
*/
|
|
1414
|
-
async handleReadme(args) {
|
|
1415
|
-
const startTime = Date.now();
|
|
1416
|
-
try {
|
|
1417
|
-
const dir = args.directory || this.currentProjectDir;
|
|
1418
|
-
// Determine which command to call
|
|
1419
|
-
const command = args.merge ? 'readme-merge' : 'readme-extract';
|
|
1420
|
-
const engineArgs = [dir];
|
|
1421
|
-
if (args.overwrite) {
|
|
1422
|
-
engineArgs.push('--overwrite');
|
|
1423
|
-
}
|
|
1424
|
-
// Call bundled readme command
|
|
1425
|
-
this.fafEngine.setWorkingDirectory(dir);
|
|
1426
|
-
const result = await this.fafEngine.callEngine(command, engineArgs);
|
|
1427
|
-
const duration = Date.now() - startTime;
|
|
1428
|
-
if (result.success && result.data) {
|
|
1429
|
-
const extracted = result.data.extracted;
|
|
1430
|
-
const fieldsExtracted = extracted ? Object.keys(extracted).filter(k => k !== 'confidence' && extracted[k]).length : 0;
|
|
1431
|
-
const confidence = extracted?.confidence?.overall || 0;
|
|
1432
|
-
const confidencePercent = Math.round(confidence * 100);
|
|
1433
|
-
// Build extracted fields display
|
|
1434
|
-
let extractedDisplay = '';
|
|
1435
|
-
if (extracted) {
|
|
1436
|
-
const fields = ['who', 'what', 'where', 'why', 'when', 'how'];
|
|
1437
|
-
for (const field of fields) {
|
|
1438
|
-
if (extracted[field]) {
|
|
1439
|
-
extractedDisplay += `\n**${field.toUpperCase()}:** ${extracted[field]}`;
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
}
|
|
1443
|
-
let message = `${result.data.message}\n\n` +
|
|
1444
|
-
`**README:** ${result.data.readmePath}\n` +
|
|
1445
|
-
`**Confidence:** ${confidencePercent}%\n` +
|
|
1446
|
-
`**Fields found:** ${fieldsExtracted}/6\n` +
|
|
1447
|
-
extractedDisplay;
|
|
1448
|
-
if (args.merge) {
|
|
1449
|
-
const fieldsUpdated = result.data.fieldsUpdated || [];
|
|
1450
|
-
message += `\n\n**Merged fields:** ${fieldsUpdated.join(', ')}\n\n` +
|
|
1451
|
-
`**Next steps:**\n` +
|
|
1452
|
-
`1. Run \`faf_score\` to see your new AI-readiness score\n` +
|
|
1453
|
-
`2. Fill any missing fields with \`faf_human_add\` or visit faf.one/6ws\n` +
|
|
1454
|
-
`3. Your context is now available to all AI assistants`;
|
|
1455
|
-
}
|
|
1456
|
-
else {
|
|
1457
|
-
message += `\n\n**Next steps:**\n` +
|
|
1458
|
-
`1. Run \`faf_readme { merge: true }\` to merge into project.faf\n` +
|
|
1459
|
-
`2. Or manually copy the extracted context\n` +
|
|
1460
|
-
`3. Fill any missing fields at faf.one/6ws`;
|
|
1461
|
-
}
|
|
1462
|
-
return await this.formatResult('š README Context', message, duration, dir);
|
|
1463
|
-
}
|
|
1464
|
-
else {
|
|
1465
|
-
return await this.formatResult('š README Context', result.error || 'Failed to extract context from README', duration, dir);
|
|
1466
|
-
}
|
|
1467
|
-
}
|
|
1468
|
-
catch (error) {
|
|
1469
|
-
const duration = Date.now() - startTime;
|
|
1470
|
-
return await this.formatResult('š README Context', `Error: ${error.message}`, duration);
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
async handleShare(args) {
|
|
1474
|
-
const message = args.sanitize ? 'š Sanitized and ready to share!' : 'š Share link: faf.one/share/abc123';
|
|
1475
|
-
return await this.formatResult('š FAF Share', message);
|
|
1476
|
-
}
|
|
1477
|
-
// AI Suite Handlers
|
|
1478
|
-
async handleEnhance(args) {
|
|
1479
|
-
// ā” USE THE FAF ENGINE!
|
|
1480
|
-
try {
|
|
1481
|
-
const cwd = process.cwd();
|
|
1482
|
-
this.fafEngine.setWorkingDirectory(cwd);
|
|
1483
|
-
const enhanceArgs = [];
|
|
1484
|
-
if (args.model) {
|
|
1485
|
-
enhanceArgs.push('--model');
|
|
1486
|
-
enhanceArgs.push(args.model);
|
|
1487
|
-
}
|
|
1488
|
-
if (args.focus) {
|
|
1489
|
-
enhanceArgs.push('--focus');
|
|
1490
|
-
enhanceArgs.push(args.focus);
|
|
1491
|
-
}
|
|
1492
|
-
const result = await this.fafEngine.callEngine('enhance', enhanceArgs);
|
|
1493
|
-
if (result.success) {
|
|
1494
|
-
const output = result.data?.output || 'Project enhanced successfully';
|
|
1495
|
-
return await this.formatResult('š FAF Enhance', output);
|
|
1496
|
-
}
|
|
1497
|
-
}
|
|
1498
|
-
catch (engineError) {
|
|
1499
|
-
console.warn('FAF Engine enhance failed, using native:', engineError);
|
|
1500
|
-
}
|
|
1501
|
-
// Fallback to simple message
|
|
1502
|
-
const model = args.model || 'claude';
|
|
1503
|
-
const focus = args.focus || 'context';
|
|
1504
|
-
return await this.formatResult('š FAF Enhance', `Enhanced with ${model} focusing on ${focus} (native fallback)`);
|
|
1505
|
-
}
|
|
1506
|
-
async handleAnalyze(args) {
|
|
1507
|
-
const models = args.models || ['claude'];
|
|
1508
|
-
return await this.formatResult('š§ FAF Analyze', `Analyzed with ${models.join(', ')}`);
|
|
1509
|
-
}
|
|
1510
|
-
async handleVerify(args) {
|
|
1511
|
-
const models = args.models || ['claude', 'gpt', 'gemini'];
|
|
1512
|
-
return await this.formatResult('ā
FAF Verify', `Verified with ${models.length} models - All good!`);
|
|
1513
|
-
}
|
|
1514
|
-
// Discovery Handlers
|
|
1515
|
-
async handleIndex(_args) {
|
|
1516
|
-
const files = await fs.readdir(process.cwd());
|
|
1517
|
-
const index = files.sort().map(f => `⢠${f}`).join('\n');
|
|
1518
|
-
return await this.formatResult('š FAF Index', `A-Z Catalog:\n${index}`);
|
|
1519
|
-
}
|
|
1520
|
-
async handleSearch(args) {
|
|
1521
|
-
const query = args.query || '';
|
|
1522
|
-
const searchType = args.type || 'filename';
|
|
1523
|
-
const searchDir = args.directory || process.cwd();
|
|
1524
|
-
if (!query) {
|
|
1525
|
-
return await this.formatResult('š FAF Search', 'Please provide a search query');
|
|
1526
|
-
}
|
|
1527
|
-
// Import native file finder
|
|
1528
|
-
const { findFiles } = await import('../faf-core/utils/native-file-finder.js');
|
|
1529
|
-
try {
|
|
1530
|
-
// For filename search, find all files matching the name
|
|
1531
|
-
if (searchType === 'filename' || searchType === 'both') {
|
|
1532
|
-
const allFiles = await findFiles(searchDir, {
|
|
1533
|
-
maxFiles: 100, // Limit to prevent overwhelming results
|
|
1534
|
-
absolute: true
|
|
1535
|
-
});
|
|
1536
|
-
// Filter files that match the query (case-insensitive)
|
|
1537
|
-
const queryLower = query.toLowerCase();
|
|
1538
|
-
const matches = allFiles.filter(filePath => {
|
|
1539
|
-
const basename = path.basename(filePath);
|
|
1540
|
-
return basename.toLowerCase().includes(queryLower);
|
|
1541
|
-
});
|
|
1542
|
-
if (matches.length === 0) {
|
|
1543
|
-
return await this.formatResult('š FAF Search', `No files found matching "${query}"\n\nSearched in: ${searchDir}`);
|
|
1544
|
-
}
|
|
1545
|
-
// Format results
|
|
1546
|
-
const resultText = matches.length === 1
|
|
1547
|
-
? `Found 1 match:\n\n${matches[0]}`
|
|
1548
|
-
: `Found ${matches.length} matches:\n\n${matches.slice(0, 20).join('\n')}${matches.length > 20 ? `\n\n... and ${matches.length - 20} more` : ''}`;
|
|
1549
|
-
return await this.formatResult('š FAF Search', resultText);
|
|
1550
|
-
}
|
|
1551
|
-
// Content search not yet implemented
|
|
1552
|
-
return await this.formatResult('š FAF Search', 'Content search not yet implemented. Use type="filename" for now.');
|
|
1553
|
-
}
|
|
1554
|
-
catch (error) {
|
|
1555
|
-
return await this.formatResult('š FAF Search Error', `Search failed: ${error.message}`);
|
|
1556
|
-
}
|
|
1557
|
-
}
|
|
1558
|
-
async handleStacks(_args) {
|
|
1559
|
-
const stacks = 'TypeScript (45%)\nNode.js (30%)\nReact (15%)\nMCP (10%)';
|
|
1560
|
-
return await this.formatResult('š FAF STACKTISTICS', stacks);
|
|
1561
|
-
}
|
|
1562
|
-
async handleFaq(args) {
|
|
1563
|
-
const topic = args.topic || 'general';
|
|
1564
|
-
let answer = '';
|
|
1565
|
-
switch (topic.toLowerCase()) {
|
|
1566
|
-
case 'general':
|
|
1567
|
-
case 'help':
|
|
1568
|
-
answer = `š FAF HELP - Championship Commands\n\n` +
|
|
1569
|
-
`š QUICK START:\n` +
|
|
1570
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1571
|
-
`faf_auto /path/to/project ā ONE COMMAND SETUP!\n` +
|
|
1572
|
-
` ā No faffing about!\n` +
|
|
1573
|
-
` ā <10ms to glory!\n\n` +
|
|
1574
|
-
`š ESSENTIAL FIVE:\n` +
|
|
1575
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1576
|
-
`1. faf_auto ā š Complete setup (start here!)\n` +
|
|
1577
|
-
`2. faf_score ā š Check your rating (aim for 100%!)\n` +
|
|
1578
|
-
`3. faf_bi_sync ā š Context-Mirroring (40ms magic)\n` +
|
|
1579
|
-
`4. faf_list ā š See your files (1ms fast)\n` +
|
|
1580
|
-
`5. faf_trust ā ā
Validation modes (4 levels)\n\n` +
|
|
1581
|
-
`š” PRO TIP:\n` +
|
|
1582
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1583
|
-
`Drop any file from your project and FAF\n` +
|
|
1584
|
-
`will find the project root automatically!\n\n` +
|
|
1585
|
-
`šÆ For specific help, try:\n` +
|
|
1586
|
-
`⢠faf_faq topic:"getting-started"\n` +
|
|
1587
|
-
`⢠faf_faq topic:"commands"\n` +
|
|
1588
|
-
`⢠faf_faq topic:"performance"\n` +
|
|
1589
|
-
`⢠faf_faq topic:"troubleshooting"\n\n` +
|
|
1590
|
-
`ā” ZERO FAF INNIT - Championship Mode!`;
|
|
1591
|
-
break;
|
|
1592
|
-
case 'getting-started':
|
|
1593
|
-
case 'start':
|
|
1594
|
-
case 'begin':
|
|
1595
|
-
answer = `š GETTING STARTED WITH FAF\n\n` +
|
|
1596
|
-
`Step 1: Initialize Everything\n` +
|
|
1597
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1598
|
-
`faf_auto ~/your-project\n\n` +
|
|
1599
|
-
`What happens:\n` +
|
|
1600
|
-
`⢠Scans your entire project\n` +
|
|
1601
|
-
`⢠Detects your tech stack\n` +
|
|
1602
|
-
`⢠Creates .faf with intelligence\n` +
|
|
1603
|
-
`⢠Generates CLAUDE.md for humans\n` +
|
|
1604
|
-
`⢠Activates Context-Mirroring\n` +
|
|
1605
|
-
`⢠Calculates your FAF score\n\n` +
|
|
1606
|
-
`Step 2: Check Your Score\n` +
|
|
1607
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1608
|
-
`faf_score\n\n` +
|
|
1609
|
-
`Scoring (Mk3 Tier System):\n` +
|
|
1610
|
-
`⢠š“ <55%: AI working blind\n` +
|
|
1611
|
-
`⢠š” 55%+: Needs improvement\n` +
|
|
1612
|
-
`⢠š¢ 70%+: Solid foundation\n` +
|
|
1613
|
-
`⢠š„ 85%+: Bronze - Production ready\n` +
|
|
1614
|
-
`⢠š„ 95%+: Silver - Excellent\n` +
|
|
1615
|
-
`⢠š„ 99%+: Gold - Exceptional\n` +
|
|
1616
|
-
`⢠š 100%: Trophy - Perfect!\n\n` +
|
|
1617
|
-
`That's it! You're ready to go! ā”`;
|
|
1618
|
-
break;
|
|
1619
|
-
case 'commands':
|
|
1620
|
-
case 'functions':
|
|
1621
|
-
case 'tools':
|
|
1622
|
-
answer = `š FAF COMMAND CATEGORIES\n\n` +
|
|
1623
|
-
`Core Commands:\n` +
|
|
1624
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1625
|
-
`⢠faf_auto - Complete setup (start here!)\n` +
|
|
1626
|
-
`⢠faf_init - Initialize FAF\n` +
|
|
1627
|
-
`⢠faf_score - Check your rating\n` +
|
|
1628
|
-
`⢠faf_status - Project overview\n\n` +
|
|
1629
|
-
`Sync & Mirror:\n` +
|
|
1630
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1631
|
-
`⢠faf_sync - One-way sync\n` +
|
|
1632
|
-
`⢠faf_bi_sync - Two-way Context-Mirror\n\n` +
|
|
1633
|
-
`Trust System (4 Modes):\n` +
|
|
1634
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1635
|
-
`⢠faf_trust confidence - Daily checks\n` +
|
|
1636
|
-
`⢠faf_trust garage - Under the hood\n` +
|
|
1637
|
-
`⢠faf_trust panic - Emergency mode\n` +
|
|
1638
|
-
`⢠faf_trust validated - Production seal\n\n` +
|
|
1639
|
-
`File Operations:\n` +
|
|
1640
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1641
|
-
`⢠faf_read, faf_write, faf_list\n` +
|
|
1642
|
-
`⢠faf_exists, faf_delete, faf_move\n` +
|
|
1643
|
-
`⢠faf_copy, faf_mkdir\n\n` +
|
|
1644
|
-
`50+ tools total! 21 Core ⢠30+ Advanced\n` +
|
|
1645
|
-
`Type any command for details.`;
|
|
1646
|
-
break;
|
|
1647
|
-
case 'performance':
|
|
1648
|
-
case 'speed':
|
|
1649
|
-
case 'fast':
|
|
1650
|
-
answer = `ā” FAF PERFORMANCE\n\n` +
|
|
1651
|
-
`Speed Benchmarks:\n` +
|
|
1652
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1653
|
-
`⢠faf_check ā 0ms (SUB-MILLISECOND!)\n` +
|
|
1654
|
-
`⢠faf_list ā 1ms\n` +
|
|
1655
|
-
`⢠faf_score ā 2ms\n` +
|
|
1656
|
-
`⢠faf_init ā 6ms\n` +
|
|
1657
|
-
`⢠faf_auto ā 9ms\n` +
|
|
1658
|
-
`⢠Most ops ā <10ms\n\n` +
|
|
1659
|
-
`Speed Classifications:\n` +
|
|
1660
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1661
|
-
`ā” <10ms = Instant\n` +
|
|
1662
|
-
`š 10-50ms = Fast\n` +
|
|
1663
|
-
`ā
50-100ms = Normal\n` +
|
|
1664
|
-
`ā³ >100ms = Large operations\n\n` +
|
|
1665
|
-
`The Secret:\n` +
|
|
1666
|
-
`⢠Native TypeScript (no shell)\n` +
|
|
1667
|
-
`⢠Context-Mirroring (not copying)\n` +
|
|
1668
|
-
`⢠Zero dependencies for core\n` +
|
|
1669
|
-
`⢠Some ops too fast to measure!`;
|
|
1670
|
-
break;
|
|
1671
|
-
case 'troubleshooting':
|
|
1672
|
-
case 'error':
|
|
1673
|
-
case 'problem':
|
|
1674
|
-
case 'help!':
|
|
1675
|
-
answer = `š§ TROUBLESHOOTING\n\n` +
|
|
1676
|
-
`"EROFS: read-only file system"\n` +
|
|
1677
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1678
|
-
`You're in your MCP host sandbox!\n` +
|
|
1679
|
-
`Solution: Use real path\n` +
|
|
1680
|
-
`Example: faf_auto ~/Documents/project\n\n` +
|
|
1681
|
-
`"Stack: Unknown"\n` +
|
|
1682
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1683
|
-
`FAF couldn't detect your stack.\n` +
|
|
1684
|
-
`Solution: We check package.json\n` +
|
|
1685
|
-
`Working on: .svelte-kit detection\n\n` +
|
|
1686
|
-
`"Permission modal keeps appearing"\n` +
|
|
1687
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1688
|
-
`Click "Always Allow" once.\n` +
|
|
1689
|
-
`We've added file:// resources.\n` +
|
|
1690
|
-
`Should be fixed in v${version_js_1.VERSION}!\n\n` +
|
|
1691
|
-
`"Where do I start?"\n` +
|
|
1692
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1693
|
-
`Always: faf_auto /your/project\n` +
|
|
1694
|
-
`It does EVERYTHING!`;
|
|
1695
|
-
break;
|
|
1696
|
-
case 'philosophy':
|
|
1697
|
-
case 'why':
|
|
1698
|
-
case 'about':
|
|
1699
|
-
answer = `š THE FAF PHILOSOPHY\n\n` +
|
|
1700
|
-
`We ARE the C in MCP:\n` +
|
|
1701
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1702
|
-
`Model(s) need Context\n` +
|
|
1703
|
-
`Context needs Protocol\n` +
|
|
1704
|
-
`FAF provides the Context!\n` +
|
|
1705
|
-
`Without FAF, MCP is just MP!\n\n` +
|
|
1706
|
-
`Core Beliefs:\n` +
|
|
1707
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1708
|
-
`⢠ZERO FAF INNIT (no faffing about)\n` +
|
|
1709
|
-
`⢠Every bug ā step closer to 99\n` +
|
|
1710
|
-
`⢠Context-Mirroring > file syncing\n` +
|
|
1711
|
-
`⢠Award credit, not track debt\n` +
|
|
1712
|
-
`⢠Championship performance only\n\n` +
|
|
1713
|
-
`F1-Inspired Engineering:\n` +
|
|
1714
|
-
`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n` +
|
|
1715
|
-
`⢠Best engineering\n` +
|
|
1716
|
-
`⢠Built for speed\n` +
|
|
1717
|
-
`⢠Award-winning intent\n` +
|
|
1718
|
-
`⢠No reverse gear, only forward!\n\n` +
|
|
1719
|
-
`Result: š 100% Trophy - Championship Complete!`;
|
|
1720
|
-
break;
|
|
1721
|
-
default:
|
|
1722
|
-
answer = `ā Topic "${topic}" not found.\n\n` +
|
|
1723
|
-
`Try these topics:\n` +
|
|
1724
|
-
`⢠general (or just faf_faq)\n` +
|
|
1725
|
-
`⢠getting-started\n` +
|
|
1726
|
-
`⢠commands\n` +
|
|
1727
|
-
`⢠performance\n` +
|
|
1728
|
-
`⢠troubleshooting\n` +
|
|
1729
|
-
`⢠philosophy\n\n` +
|
|
1730
|
-
`Or just run: faf_auto /your/project\n` +
|
|
1731
|
-
`It's the answer to most questions! šļøā”`;
|
|
1732
|
-
}
|
|
1733
|
-
return await this.formatResult('š” FAF HELP', answer);
|
|
1734
|
-
}
|
|
1735
|
-
async handleGuide(_args) {
|
|
1736
|
-
const guide = `# FAF MCP - your MCP host Guide
|
|
1737
|
-
|
|
1738
|
-
## Core Principle: Local Path First
|
|
1739
|
-
|
|
1740
|
-
your MCP host has full filesystem access with local paths. All 52 MCP tools work perfectly when you provide local project paths.
|
|
1741
|
-
|
|
1742
|
-
**The Pattern:**
|
|
1743
|
-
1. Ask: "What's your project path?"
|
|
1744
|
-
2. For new projects, suggest: \`~/Projects/[project-name]\`
|
|
1745
|
-
3. For existing projects, use their exact path
|
|
1746
|
-
|
|
1747
|
-
## Path Resolution
|
|
1748
|
-
|
|
1749
|
-
**New Projects:**
|
|
1750
|
-
- Suggest normalized paths: \`~/Projects/heritage-club-dubai\`
|
|
1751
|
-
- Convert spaces to hyphens, lowercase preferred
|
|
1752
|
-
- Confirm before creating
|
|
1753
|
-
|
|
1754
|
-
**Existing Projects:**
|
|
1755
|
-
- Ask for current location
|
|
1756
|
-
- Use exact path provided
|
|
1757
|
-
- No guessing, no auto-detection
|
|
1758
|
-
|
|
1759
|
-
## What Works
|
|
1760
|
-
|
|
1761
|
-
āļø \`~/Projects/my-app\` (macOS/Linux)
|
|
1762
|
-
āļø \`/Users/username/Projects/my-app\` (absolute)
|
|
1763
|
-
āļø \`C:\\Users\\username\\Projects\\my-app\` (Windows)
|
|
1764
|
-
|
|
1765
|
-
## What Doesn't Work
|
|
1766
|
-
|
|
1767
|
-
Container paths like \`/mnt/user-data/\` are incompatible with MCP tools.
|
|
1768
|
-
|
|
1769
|
-
## Migration Path
|
|
1770
|
-
|
|
1771
|
-
Old \`.faf\` files ā new \`project.faf\` format:
|
|
1772
|
-
|
|
1773
|
-
\`\`\`bash
|
|
1774
|
-
faf_migrate directory:"/path/to/project"
|
|
1775
|
-
\`\`\`
|
|
1776
|
-
|
|
1777
|
-
This upgrades to visible format v2.5.0, sitting alongside package.json and README.md.
|
|
1778
|
-
|
|
1779
|
-
## Command Examples
|
|
1780
|
-
|
|
1781
|
-
All commands need local paths:
|
|
1782
|
-
|
|
1783
|
-
- \`faf_init directory:"~/Projects/my-app"\`
|
|
1784
|
-
- \`faf_score directory:"~/Projects/my-app"\`
|
|
1785
|
-
- \`faf_sync directory:"~/Projects/my-app"\`
|
|
1786
|
-
- \`faf_migrate directory:"~/Projects/old-project"\`
|
|
1787
|
-
|
|
1788
|
-
## UX Pattern
|
|
1789
|
-
|
|
1790
|
-
User: "Create a .faf"
|
|
1791
|
-
Claude: "Project name?"
|
|
1792
|
-
User: "my-app"
|
|
1793
|
-
Claude: "Creating at ~/Projects/my-app/"
|
|
1794
|
-
|
|
1795
|
-
Simple, fast, championship-grade.`;
|
|
1796
|
-
return {
|
|
1797
|
-
content: [{
|
|
1798
|
-
type: 'text',
|
|
1799
|
-
text: guide
|
|
1800
|
-
}]
|
|
1801
|
-
};
|
|
1802
|
-
}
|
|
1803
|
-
// Developer Tool Handlers
|
|
1804
|
-
async handleStatus(args) {
|
|
1805
|
-
const targetDir = args?.directory || process.cwd();
|
|
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);
|
|
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.`;
|
|
1814
|
-
return await this.formatResult('š FAF Status', output, undefined, targetDir);
|
|
1815
|
-
}
|
|
1816
|
-
/**
|
|
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.
|
|
1821
|
-
*/
|
|
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) {
|
|
1827
|
-
return {
|
|
1828
|
-
found: false,
|
|
1829
|
-
score: 0,
|
|
1830
|
-
tierName: 'White',
|
|
1831
|
-
tierGlyph: 'ā”',
|
|
1832
|
-
tierDisplay: 'ā” no .faf',
|
|
1833
|
-
nextTier: null,
|
|
1834
|
-
populated: 0,
|
|
1835
|
-
total: 0,
|
|
1836
|
-
};
|
|
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
|
-
};
|
|
1850
|
-
}
|
|
1851
|
-
async handleCheck(_args) {
|
|
1852
|
-
return await this.formatResult('ā
FAF Check', 'All systems operational!');
|
|
1853
|
-
}
|
|
1854
|
-
async handleClear(args) {
|
|
1855
|
-
const what = args.all ? 'everything' : args.cache ? 'cache' : 'temp files';
|
|
1856
|
-
return await this.formatResult('š§¹ FAF Clear', `Cleared ${what}`);
|
|
1857
|
-
}
|
|
1858
|
-
async handleEdit(args) {
|
|
1859
|
-
const filePath = args.path || '.faf';
|
|
1860
|
-
return await this.formatResult('āļø FAF Edit', `Editing ${filePath} (interactive mode)`);
|
|
1861
|
-
}
|
|
1862
|
-
// Filesystem Operations - Native TypeScript, no shell!
|
|
1863
|
-
async handleList(args) {
|
|
1864
|
-
const files = await fs.readdir(args.path || process.cwd(), {
|
|
1865
|
-
withFileTypes: true,
|
|
1866
|
-
recursive: args.recursive
|
|
1867
|
-
});
|
|
1868
|
-
const formatted = files.map(f => `${f.isDirectory() ? 'š' : 'š'} ${f.name}`).join('\n');
|
|
1869
|
-
return await this.formatResult('š Directory Contents', formatted);
|
|
1870
|
-
}
|
|
1871
|
-
async handleExists(args) {
|
|
1872
|
-
if (!args.path) {
|
|
1873
|
-
return await this.formatResult('ā Error', 'Path is required');
|
|
1874
|
-
}
|
|
1875
|
-
try {
|
|
1876
|
-
await fs.access(args.path);
|
|
1877
|
-
return await this.formatResult('ā
File Exists', `${args.path} exists`);
|
|
1878
|
-
}
|
|
1879
|
-
catch {
|
|
1880
|
-
return await this.formatResult('ā File Not Found', `${args.path} does not exist`);
|
|
1881
|
-
}
|
|
1882
|
-
}
|
|
1883
|
-
async handleDelete(args) {
|
|
1884
|
-
if (!args.path) {
|
|
1885
|
-
return await this.formatResult('ā Error', 'Path is required');
|
|
1886
|
-
}
|
|
1887
|
-
await fs.rm(args.path, { recursive: args.recursive, force: true });
|
|
1888
|
-
return await this.formatResult('šļø Deleted', `Removed ${args.path}`);
|
|
1889
|
-
}
|
|
1890
|
-
async handleMove(args) {
|
|
1891
|
-
if (!args.from || !args.to) {
|
|
1892
|
-
return await this.formatResult('ā Error', 'Both from and to paths are required');
|
|
1893
|
-
}
|
|
1894
|
-
await fs.rename(args.from, args.to);
|
|
1895
|
-
return await this.formatResult('š¦ Moved', `${args.from} ā ${args.to}`);
|
|
1896
|
-
}
|
|
1897
|
-
async handleCopy(args) {
|
|
1898
|
-
if (!args.from || !args.to) {
|
|
1899
|
-
return await this.formatResult('ā Error', 'Both from and to paths are required');
|
|
1900
|
-
}
|
|
1901
|
-
await fs.cp(args.from, args.to, { recursive: true });
|
|
1902
|
-
return await this.formatResult('š Copied', `${args.from} ā ${args.to}`);
|
|
1903
|
-
}
|
|
1904
|
-
async handleMkdir(args) {
|
|
1905
|
-
if (!args.path) {
|
|
1906
|
-
return await this.formatResult('ā Error', 'Path is required');
|
|
1907
|
-
}
|
|
1908
|
-
await fs.mkdir(args.path, { recursive: args.recursive });
|
|
1909
|
-
return await this.formatResult('š Created', `Directory ${args.path} created`);
|
|
1910
|
-
}
|
|
1911
|
-
async handleAbout(_args) {
|
|
1912
|
-
// Check if faf-expert skill is installed
|
|
1913
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE || '/';
|
|
1914
|
-
const skillPath = path.join(homeDir, '.claude', 'skills', 'faf-expert', 'SKILL.md');
|
|
1915
|
-
const skillInstalled = await this.fileExists(skillPath);
|
|
1916
|
-
const skillStatus = skillInstalled
|
|
1917
|
-
? 'Claude Skills: faf-expert installed ā
'
|
|
1918
|
-
: 'Claude Skills: faf-expert available (not installed)\nš” Run faf_install_skill to install!';
|
|
1919
|
-
const aboutText = `<!-- CLAUDE:INSTRUCTION -->
|
|
1920
|
-
Content between DISPLAY:REQUIRED:VERBATIM tags is user-facing UX.
|
|
1921
|
-
Present verbatim, do not summarize, interpret, or reformat.
|
|
1922
|
-
Think: pit crew relaying engineer's exact instructions to driver.
|
|
1923
|
-
|
|
1924
|
-
${FILESYSTEM_CONTEXT_INSTRUCTION}
|
|
1925
|
-
<!-- /CLAUDE:INSTRUCTION -->
|
|
1926
|
-
|
|
1927
|
-
[DISPLAY:REQUIRED:VERBATIM]
|
|
1928
|
-
šÆ PASS TO USER AS-IS (DO NOT SUMMARIZE)
|
|
1929
|
-
|
|
1930
|
-
Version ${version_js_1.VERSION}
|
|
1931
|
-
š IANA Registered Format
|
|
1932
|
-
|
|
1933
|
-
50+ Tools Available
|
|
1934
|
-
21 Core ⢠30+ Advanced
|
|
1935
|
-
${skillStatus}
|
|
1936
|
-
|
|
1937
|
-
DROP or PASTE, Click & Go!
|
|
1938
|
-
|
|
1939
|
-
šÆ Got .faf? DROP or PASTE it
|
|
1940
|
-
š¦ Got project? DROP or PASTE README or package.json
|
|
1941
|
-
š¬ Starting fresh? Just ask
|
|
1942
|
-
|
|
1943
|
-
𩵠You just made Claude Happy
|
|
1944
|
-
š§” .faf AI you can TRUST
|
|
1945
|
-
IANA Registered: application/vnd.faf+yaml
|
|
1946
|
-
|
|
1947
|
-
Performance: <50ms per operation
|
|
1948
|
-
Zero shell dependencies
|
|
1949
|
-
100% native TypeScript
|
|
1950
|
-
[/DISPLAY:REQUIRED:VERBATIM]`;
|
|
1951
|
-
// Use DisplayProtocol for consistent global rendering
|
|
1952
|
-
return display_protocol_js_1.DisplayProtocol.createResponse(aboutText, {
|
|
1953
|
-
tool: 'faf_about',
|
|
1954
|
-
version: version_js_1.VERSION,
|
|
1955
|
-
timestamp: new Date().toISOString()
|
|
1956
|
-
});
|
|
1957
|
-
}
|
|
1958
|
-
async handleVersion(_args) {
|
|
1959
|
-
// MCP-only version info - fully self-contained
|
|
1960
|
-
const versionOutput = `<!-- CLAUDE:INSTRUCTION -->
|
|
1961
|
-
Content between DISPLAY:REQUIRED:VERBATIM tags is user-facing UX.
|
|
1962
|
-
Present verbatim, do not summarize, interpret, or reformat.
|
|
1963
|
-
Think: pit crew relaying engineer's exact instructions to driver.
|
|
1964
|
-
|
|
1965
|
-
${FILESYSTEM_CONTEXT_INSTRUCTION}
|
|
1966
|
-
<!-- /CLAUDE:INSTRUCTION -->
|
|
1967
|
-
|
|
1968
|
-
[DISPLAY:REQUIRED:VERBATIM]
|
|
1969
|
-
šÆ PASS TO USER AS-IS (DO NOT SUMMARIZE)
|
|
1970
|
-
|
|
1971
|
-
MCP Server: v${version_js_1.VERSION}
|
|
1972
|
-
š IANA Registered: application/vnd.faf+yaml
|
|
1973
|
-
|
|
1974
|
-
50+ Tools Available
|
|
1975
|
-
21 Core ⢠30+ Advanced
|
|
1976
|
-
Claude Skills: faf-expert to help 24/7
|
|
1977
|
-
|
|
1978
|
-
DROP or PASTE, Click & Go!
|
|
1979
|
-
|
|
1980
|
-
šÆ Got .faf? DROP or PASTE it
|
|
1981
|
-
š¦ Got project? DROP or PASTE README or package.json
|
|
1982
|
-
š¬ Starting fresh? Just ask
|
|
1983
|
-
|
|
1984
|
-
Performance: <50ms per operation
|
|
1985
|
-
100% native TypeScript
|
|
1986
|
-
[/DISPLAY:REQUIRED:VERBATIM]`;
|
|
1987
|
-
return display_protocol_js_1.DisplayProtocol.createResponse(versionOutput, {
|
|
1988
|
-
tool: 'faf_version',
|
|
1989
|
-
version: version_js_1.VERSION,
|
|
1990
|
-
timestamp: new Date().toISOString()
|
|
1991
|
-
});
|
|
1992
|
-
}
|
|
1993
|
-
async handleInnit(args) {
|
|
1994
|
-
// British wrapper around faf_init - just adds charm to the message
|
|
1995
|
-
return await this.handleInit(args);
|
|
1996
|
-
}
|
|
1997
|
-
// NEW: 10 HIGH-PRIORITY CLIāMCP Continuity Tool Handlers
|
|
1998
|
-
async handleFormats(args) {
|
|
1999
|
-
const dir = args.directory || process.cwd();
|
|
2000
|
-
if (dir === '/' || dir === '') {
|
|
2001
|
-
return await this.formatResult('š± TURBO-CAT', 'Directory required for format detection');
|
|
2002
|
-
}
|
|
2003
|
-
this.fafEngine.setWorkingDirectory(dir);
|
|
2004
|
-
const result = await this.fafEngine.callEngine('formats', []);
|
|
2005
|
-
if (!result.success) {
|
|
2006
|
-
return await this.formatResult('š± TURBO-CAT', `CLI Error: ${result.error}\n\nPlease ensure faf-cli v3.1.1+ is installed globally.`);
|
|
2007
|
-
}
|
|
2008
|
-
return await this.formatResult('š± TURBO-CAT Format Discovery', result.data?.output || 'Success');
|
|
2009
|
-
}
|
|
2010
|
-
async handleValidate(args) {
|
|
2011
|
-
const validateArgs = args.file ? [args.file] : [];
|
|
2012
|
-
const result = await this.fafEngine.callEngine('validate', validateArgs);
|
|
2013
|
-
if (!result.success) {
|
|
2014
|
-
return await this.formatResult('ā
FAF Validate', `CLI Error: ${result.error}\n\nPlease ensure faf-cli v3.1.1+ is installed globally.`);
|
|
2015
|
-
}
|
|
2016
|
-
return await this.formatResult('ā
FAF Validate', result.data?.output || 'Success');
|
|
2017
|
-
}
|
|
2018
|
-
async handleDoctor(args) {
|
|
2019
|
-
if (args.directory) {
|
|
2020
|
-
this.fafEngine.setWorkingDirectory(args.directory);
|
|
2021
|
-
}
|
|
2022
|
-
const result = await this.fafEngine.callEngine('doctor', []);
|
|
2023
|
-
if (!result.success) {
|
|
2024
|
-
return await this.formatResult('š„ FAF Doctor', `CLI Error: ${result.error}\n\nPlease ensure faf-cli v3.1.1+ is installed globally.`);
|
|
2025
|
-
}
|
|
2026
|
-
return await this.formatResult('š„ FAF Doctor', result.data?.output || 'Success');
|
|
2027
|
-
}
|
|
2028
|
-
async handleDna(args) {
|
|
2029
|
-
const dnaArgs = args.file ? [args.file] : [];
|
|
2030
|
-
const result = await this.fafEngine.callEngine('dna', dnaArgs);
|
|
2031
|
-
if (!result.success) {
|
|
2032
|
-
return await this.formatResult('𧬠FAF DNA', `CLI Error: ${result.error}\n\nPlease ensure faf-cli v3.1.1+ is installed globally.`);
|
|
2033
|
-
}
|
|
2034
|
-
return await this.formatResult('𧬠Birth DNA', result.data?.output || 'Success');
|
|
2035
|
-
}
|
|
2036
|
-
async handleLog(args) {
|
|
2037
|
-
const logArgs = [];
|
|
2038
|
-
if (args.file)
|
|
2039
|
-
logArgs.push(args.file);
|
|
2040
|
-
if (args.limit)
|
|
2041
|
-
logArgs.push('--limit', args.limit.toString());
|
|
2042
|
-
const result = await this.fafEngine.callEngine('log', logArgs);
|
|
2043
|
-
if (!result.success) {
|
|
2044
|
-
return await this.formatResult('š FAF Log', `CLI Error: ${result.error}\n\nPlease ensure faf-cli v3.1.1+ is installed globally.`);
|
|
2045
|
-
}
|
|
2046
|
-
return await this.formatResult('š DNA Evolution Log', result.data?.output || 'Success');
|
|
2047
|
-
}
|
|
2048
|
-
async handleUpdate(args) {
|
|
2049
|
-
const updateArgs = [];
|
|
2050
|
-
if (args.file)
|
|
2051
|
-
updateArgs.push(args.file);
|
|
2052
|
-
if (args.force)
|
|
2053
|
-
updateArgs.push('--force');
|
|
2054
|
-
const result = await this.fafEngine.callEngine('update', updateArgs);
|
|
2055
|
-
if (!result.success) {
|
|
2056
|
-
return await this.formatResult('š FAF Update', `CLI Error: ${result.error}\n\nPlease ensure faf-cli v3.1.1+ is installed globally.`);
|
|
2057
|
-
}
|
|
2058
|
-
return await this.formatResult('š FAF Update', result.data?.output || 'Success');
|
|
2059
|
-
}
|
|
2060
|
-
async handleRecover(args) {
|
|
2061
|
-
const recoverArgs = [];
|
|
2062
|
-
if (args.file)
|
|
2063
|
-
recoverArgs.push(args.file);
|
|
2064
|
-
if (args.timestamp)
|
|
2065
|
-
recoverArgs.push('--timestamp', args.timestamp);
|
|
2066
|
-
const result = await this.fafEngine.callEngine('recover', recoverArgs);
|
|
2067
|
-
if (!result.success) {
|
|
2068
|
-
return await this.formatResult('š FAF Recover', `CLI Error: ${result.error}\n\nPlease ensure faf-cli v3.1.1+ is installed globally.`);
|
|
2069
|
-
}
|
|
2070
|
-
return await this.formatResult('š FAF Recovery', result.data?.output || 'Success');
|
|
2071
|
-
}
|
|
2072
|
-
async handleAuth(args) {
|
|
2073
|
-
const authArgs = args.action ? [args.action] : [];
|
|
2074
|
-
const result = await this.fafEngine.callEngine('auth', authArgs);
|
|
2075
|
-
if (!result.success) {
|
|
2076
|
-
return await this.formatResult('š FAF Auth', `CLI Error: ${result.error}\n\nPlease ensure faf-cli v3.1.1+ is installed globally.`);
|
|
2077
|
-
}
|
|
2078
|
-
return await this.formatResult('š FAF Authentication', result.data?.output || 'Success');
|
|
2079
|
-
}
|
|
2080
|
-
async handleAudit(args) {
|
|
2081
|
-
const auditArgs = [];
|
|
2082
|
-
if (args.file)
|
|
2083
|
-
auditArgs.push(args.file);
|
|
2084
|
-
if (args.detailed)
|
|
2085
|
-
auditArgs.push('--detailed');
|
|
2086
|
-
const result = await this.fafEngine.callEngine('audit', auditArgs);
|
|
2087
|
-
if (!result.success) {
|
|
2088
|
-
return await this.formatResult('š FAF Audit', `CLI Error: ${result.error}\n\nPlease ensure faf-cli v3.1.1+ is installed globally.`);
|
|
2089
|
-
}
|
|
2090
|
-
return await this.formatResult('š FAF Audit Report', result.data?.output || 'Success');
|
|
2091
|
-
}
|
|
2092
|
-
async handleMigrate(args) {
|
|
2093
|
-
const migrateArgs = [];
|
|
2094
|
-
if (args.directory) {
|
|
2095
|
-
this.fafEngine.setWorkingDirectory(args.directory);
|
|
2096
|
-
}
|
|
2097
|
-
if (args.backup === false)
|
|
2098
|
-
migrateArgs.push('--no-backup');
|
|
2099
|
-
const result = await this.fafEngine.callEngine('migrate', migrateArgs);
|
|
2100
|
-
if (!result.success) {
|
|
2101
|
-
return await this.formatResult('š FAF Migrate', `CLI Error: ${result.error}\n\nPlease ensure faf-cli v3.1.1+ is installed globally.`);
|
|
2102
|
-
}
|
|
2103
|
-
return await this.formatResult('š FAF Migration', result.data?.output || 'Success');
|
|
2104
|
-
}
|
|
2105
|
-
async handleRead(args) {
|
|
2106
|
-
const content = await fs.readFile(args.path, 'utf-8');
|
|
2107
|
-
return await this.formatResult('š File Contents', content);
|
|
2108
|
-
}
|
|
2109
|
-
async handleWrite(args) {
|
|
2110
|
-
await fs.writeFile(args.path, args.content);
|
|
2111
|
-
return await this.formatResult('š¾ File Written', `Saved to ${args.path}`);
|
|
2112
|
-
}
|
|
2113
|
-
async handleSkills(args) {
|
|
2114
|
-
const dir = args?.directory || this.currentProjectDir;
|
|
2115
|
-
const startTime = Date.now();
|
|
2116
|
-
try {
|
|
2117
|
-
// Call faf-cli skills command
|
|
2118
|
-
this.fafEngine.setWorkingDirectory(dir);
|
|
2119
|
-
const result = await this.fafEngine.callEngine('skills', []);
|
|
2120
|
-
const duration = Date.now() - startTime;
|
|
2121
|
-
if (result.success && result.data?.output) {
|
|
2122
|
-
return await this.formatResult('šø Claude Code Skills', result.data.output, duration, dir);
|
|
2123
|
-
}
|
|
2124
|
-
else {
|
|
2125
|
-
return await this.formatResult('šø Skills', 'No skills configured in .faf file', duration, dir);
|
|
2126
|
-
}
|
|
2127
|
-
}
|
|
2128
|
-
catch (error) {
|
|
2129
|
-
const duration = Date.now() - startTime;
|
|
2130
|
-
return await this.formatResult('šø Skills', `Error: ${error.message}`, duration, dir);
|
|
2131
|
-
}
|
|
2132
|
-
}
|
|
2133
|
-
async handleInstallSkill(_args) {
|
|
2134
|
-
const startTime = Date.now();
|
|
2135
|
-
try {
|
|
2136
|
-
// Find the skill file in the npm package
|
|
2137
|
-
// It should be at: node_modules/faf-mcp/skill/SKILL.md
|
|
2138
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE || '/';
|
|
2139
|
-
const claudeSkillsDir = path.join(homeDir, '.claude', 'skills', 'faf-expert');
|
|
2140
|
-
const targetSkillPath = path.join(claudeSkillsDir, 'SKILL.md');
|
|
2141
|
-
// Find source skill file - check multiple possible locations
|
|
2142
|
-
let sourceSkillPath = null;
|
|
2143
|
-
// Location 1: If this is the dev repo
|
|
2144
|
-
const devRepoPath = path.join(__dirname, '../../skill/SKILL.md');
|
|
2145
|
-
if (await this.fileExists(devRepoPath)) {
|
|
2146
|
-
sourceSkillPath = devRepoPath;
|
|
2147
|
-
}
|
|
2148
|
-
// Location 2: In node_modules (global or local)
|
|
2149
|
-
if (!sourceSkillPath) {
|
|
2150
|
-
const globalNodeModules = path.join(homeDir, '.npm', 'lib', 'node_modules', 'faf-mcp', 'skill', 'SKILL.md');
|
|
2151
|
-
if (await this.fileExists(globalNodeModules)) {
|
|
2152
|
-
sourceSkillPath = globalNodeModules;
|
|
2153
|
-
}
|
|
2154
|
-
}
|
|
2155
|
-
// Location 3: In current working directory node_modules
|
|
2156
|
-
if (!sourceSkillPath) {
|
|
2157
|
-
const localNodeModules = path.join(process.cwd(), 'node_modules', 'faf-mcp', 'skill', 'SKILL.md');
|
|
2158
|
-
if (await this.fileExists(localNodeModules)) {
|
|
2159
|
-
sourceSkillPath = localNodeModules;
|
|
2160
|
-
}
|
|
2161
|
-
}
|
|
2162
|
-
// Location 4: Search using require.resolve
|
|
2163
|
-
if (!sourceSkillPath) {
|
|
2164
|
-
try {
|
|
2165
|
-
const mcpPackageRoot = path.dirname(require.resolve('faf-mcp/package.json'));
|
|
2166
|
-
const resolvedPath = path.join(mcpPackageRoot, 'skill', 'SKILL.md');
|
|
2167
|
-
if (await this.fileExists(resolvedPath)) {
|
|
2168
|
-
sourceSkillPath = resolvedPath;
|
|
2169
|
-
}
|
|
2170
|
-
}
|
|
2171
|
-
catch (e) {
|
|
2172
|
-
// require.resolve failed, continue
|
|
2173
|
-
}
|
|
2174
|
-
}
|
|
2175
|
-
if (!sourceSkillPath) {
|
|
2176
|
-
const duration = Date.now() - startTime;
|
|
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);
|
|
2178
|
-
}
|
|
2179
|
-
// Create directory if needed
|
|
2180
|
-
await fs.mkdir(claudeSkillsDir, { recursive: true });
|
|
2181
|
-
// Copy skill file
|
|
2182
|
-
const skillContent = await fs.readFile(sourceSkillPath, 'utf-8');
|
|
2183
|
-
await fs.writeFile(targetSkillPath, skillContent, 'utf-8');
|
|
2184
|
-
const duration = Date.now() - startTime;
|
|
2185
|
-
return await this.formatResult('š Install faf-expert Skill', `ā
faf-expert skill installed successfully!\n\n` +
|
|
2186
|
-
`š Location: ${targetSkillPath}\n\n` +
|
|
2187
|
-
`š RESTART REQUIRED:\n` +
|
|
2188
|
-
` Please restart your MCP host to activate the skill.\n\n` +
|
|
2189
|
-
`šÆ Once restarted, invoke the faf-expert skill to reach\n` +
|
|
2190
|
-
` 99/100 AI-readiness with championship-grade guidance!\n\n` +
|
|
2191
|
-
`š” Usage: Just say "Invoke faf-expert skill" in your MCP host`, duration);
|
|
2192
|
-
}
|
|
2193
|
-
catch (error) {
|
|
2194
|
-
const duration = Date.now() - startTime;
|
|
2195
|
-
return await this.formatResult('š Install faf-expert Skill', `Error: ${error.message}`, duration);
|
|
2196
|
-
}
|
|
2197
|
-
}
|
|
2198
|
-
async handleChoose(args) {
|
|
2199
|
-
const scanDir = args?.scan_dir || process.env.HOME || '/';
|
|
2200
|
-
// Scan for projects
|
|
2201
|
-
const projects = [];
|
|
2202
|
-
// Wolfejam.dev project directories ā”
|
|
2203
|
-
const projectPaths = [
|
|
2204
|
-
path.join(scanDir, 'wolfejam.dev'), // Primary wolfejam.dev folder
|
|
2205
|
-
path.join(scanDir, 'FAF'), // FAF ecosystem
|
|
2206
|
-
path.join(scanDir, 'Projects'), // General projects
|
|
2207
|
-
path.join(scanDir, 'projects'),
|
|
2208
|
-
path.join(scanDir, 'Dev'),
|
|
2209
|
-
path.join(scanDir, 'dev'),
|
|
2210
|
-
path.join(scanDir, 'Sites'), // Websites
|
|
2211
|
-
path.join(scanDir, 'sites'),
|
|
2212
|
-
path.join(scanDir, 'Code'), // Code repos
|
|
2213
|
-
path.join(scanDir, 'code'),
|
|
2214
|
-
scanDir // Also scan root of provided dir
|
|
2215
|
-
];
|
|
2216
|
-
for (const projPath of projectPaths) {
|
|
2217
|
-
if (await this.fileExists(projPath)) {
|
|
2218
|
-
try {
|
|
2219
|
-
const dirs = await fs.readdir(projPath, { withFileTypes: true });
|
|
2220
|
-
for (const dir of dirs) {
|
|
2221
|
-
if (dir.isDirectory() && !dir.name.startsWith('.')) {
|
|
2222
|
-
const fullPath = path.join(projPath, dir.name);
|
|
2223
|
-
// Check if it's a real project
|
|
2224
|
-
const hasPackage = await this.fileExists(path.join(fullPath, 'package.json'));
|
|
2225
|
-
const hasFaf = await (0, faf_file_finder_js_1.hasFafFile)(fullPath);
|
|
2226
|
-
if (hasPackage || hasFaf) {
|
|
2227
|
-
// Real faf-cli score (0 when the project has no .faf ā honest)
|
|
2228
|
-
const score = this.getFafScore(fullPath).score;
|
|
2229
|
-
projects.push({
|
|
2230
|
-
name: dir.name,
|
|
2231
|
-
path: fullPath,
|
|
2232
|
-
score: score,
|
|
2233
|
-
initialized: hasFaf
|
|
2234
|
-
});
|
|
2235
|
-
}
|
|
2236
|
-
}
|
|
2237
|
-
}
|
|
2238
|
-
}
|
|
2239
|
-
catch (e) {
|
|
2240
|
-
// Skip inaccessible directories
|
|
2241
|
-
}
|
|
2242
|
-
}
|
|
2243
|
-
}
|
|
2244
|
-
// Sort by score (highest first)
|
|
2245
|
-
projects.sort((a, b) => b.score - a.score);
|
|
2246
|
-
// Filter out non-wolfejam.dev projects
|
|
2247
|
-
const wolfjamProjects = projects.filter(p => {
|
|
2248
|
-
const isWolfejam = p.path.includes('wolfejam') ||
|
|
2249
|
-
p.path.includes('FAF') ||
|
|
2250
|
-
p.name.toLowerCase().includes('faf') ||
|
|
2251
|
-
p.name === 'cli' ||
|
|
2252
|
-
p.name === 'claude-faf-mcp';
|
|
2253
|
-
const isExcluded = p.name.toLowerCase().includes('gallery') ||
|
|
2254
|
-
p.name.toLowerCase().includes('svelte') ||
|
|
2255
|
-
p.name.toLowerCase().includes('heritage');
|
|
2256
|
-
return isWolfejam && !isExcluded;
|
|
2257
|
-
});
|
|
2258
|
-
// GitHub Desktop Style Interface ā”
|
|
2259
|
-
let menu = `\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā®\n`;
|
|
2260
|
-
menu += `ā šļøā” wolfejam.dev Projects ā\n`;
|
|
2261
|
-
menu += `āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤\n`;
|
|
2262
|
-
// Show wolfejam.dev projects first
|
|
2263
|
-
const topProjects = wolfjamProjects.slice(0, 8);
|
|
2264
|
-
if (topProjects.length > 0) {
|
|
2265
|
-
topProjects.forEach((proj, idx) => {
|
|
2266
|
-
const scoreIcon = proj.score >= 90 ? 'š' : proj.score >= 70 ? 'ā' : 'š';
|
|
2267
|
-
const name = proj.name.substring(0, 30).padEnd(30);
|
|
2268
|
-
const score = `${proj.score}%`.padStart(4);
|
|
2269
|
-
menu += `ā ${(idx + 1).toString().padStart(2)}. ${scoreIcon} ${name} ${score} ā\n`;
|
|
2270
|
-
});
|
|
2271
|
-
}
|
|
2272
|
-
else {
|
|
2273
|
-
menu += `ā No wolfejam.dev projects found ā\n`;
|
|
2274
|
-
}
|
|
2275
|
-
menu += `āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤\n`;
|
|
2276
|
-
menu += `ā [N] ā New FAF Project ā\n`;
|
|
2277
|
-
menu += `ā [B] ā Browse for project... ā\n`;
|
|
2278
|
-
menu += `ā [R] ā Recent (last 5 used) ā\n`;
|
|
2279
|
-
menu += `ā°āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāÆ\n\n`;
|
|
2280
|
-
menu += `**šļøā” The Wolfejam Way:**\n`;
|
|
2281
|
-
menu += `⢠Select project by number (1-8)\n`;
|
|
2282
|
-
menu += `⢠Or drop any file ā type **faf**\n`;
|
|
2283
|
-
menu += `⢠Championship mode: **faf_auto "/path"**\n\n`;
|
|
2284
|
-
if (wolfjamProjects.length > 0) {
|
|
2285
|
-
menu += `**Active wolfejam.dev Projects (${wolfjamProjects.length} total):**\n\n`;
|
|
2286
|
-
wolfjamProjects.forEach((proj, idx) => {
|
|
2287
|
-
const icon = proj.score >= 90 ? 'š' : proj.score >= 70 ? 'ā' : proj.initialized ? 'š' : 'š';
|
|
2288
|
-
menu += `${icon} **${proj.name}** - ${proj.score}/100\n`;
|
|
2289
|
-
menu += ` \`${proj.path}\`\n`;
|
|
2290
|
-
if (!proj.initialized) {
|
|
2291
|
-
menu += ` ā” Quick init: \`faf_auto "${proj.path}"\`\n`;
|
|
2292
|
-
}
|
|
2293
|
-
if (idx < 3)
|
|
2294
|
-
menu += `\n`; // Only show first 3 in detail
|
|
2295
|
-
if (idx === 3)
|
|
2296
|
-
menu += `\n ... and ${wolfjamProjects.length - 3} more projects\n`;
|
|
2297
|
-
if (idx >= 3)
|
|
2298
|
-
return; // Stop after first 3
|
|
2299
|
-
});
|
|
2300
|
-
}
|
|
2301
|
-
else {
|
|
2302
|
-
menu += `**Setting up wolfejam.dev workspace...**\n\n`;
|
|
2303
|
-
menu += `ā” Quick Start:\n`;
|
|
2304
|
-
menu += `⢠Drop any project file\n`;
|
|
2305
|
-
menu += `⢠Run: \`faf_auto\`\n`;
|
|
2306
|
-
menu += `⢠Or: \`faf_choose "/path/to/wolfejam.dev"\`\n`;
|
|
2307
|
-
}
|
|
2308
|
-
menu += `\nāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n`;
|
|
2309
|
-
menu += `š” **PRO TIP:** Drop any file ā type \`faf\` ā 99% ready!\n`;
|
|
2310
|
-
menu += `šļøā” wolfejam.dev - Championship Software!`;
|
|
2311
|
-
// Use DisplayProtocol for consistent global rendering
|
|
2312
|
-
return display_protocol_js_1.DisplayProtocol.createResponse(menu, {
|
|
2313
|
-
tool: 'faf_choose',
|
|
2314
|
-
projectCount: wolfjamProjects.length,
|
|
2315
|
-
timestamp: new Date().toISOString()
|
|
2316
|
-
});
|
|
2317
|
-
}
|
|
2318
|
-
}
|
|
2319
|
-
exports.ChampionshipToolHandler = ChampionshipToolHandler;
|
|
2320
|
-
//# sourceMappingURL=championship-tools.js.map
|