faf-mcp 3.0.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -2
- package/CLAUDE.md +6 -2
- package/README.md +28 -18
- package/dist/src/faf-core/commands/agents.d.ts +2 -2
- package/dist/src/faf-core/commands/agents.js +2 -2
- package/dist/src/faf-core/commands/claude.d.ts +31 -0
- package/dist/src/faf-core/commands/{bi-sync.js → claude.js} +18 -13
- package/dist/src/faf-core/commands/claude.js.map +1 -0
- package/dist/src/faf-core/commands/conductor.d.ts +1 -1
- package/dist/src/faf-core/commands/conductor.js +1 -1
- package/dist/src/faf-core/commands/cursor.d.ts +2 -2
- package/dist/src/faf-core/commands/cursor.js +2 -2
- package/dist/src/faf-core/commands/gemini.d.ts +2 -2
- package/dist/src/faf-core/commands/gemini.js +2 -2
- package/dist/src/faf-core/commands/git-context.d.ts +1 -1
- package/dist/src/faf-core/commands/git-context.js +2 -2
- package/dist/src/faf-core/commands/git-context.js.map +1 -1
- package/dist/src/faf-core/parsers/agents-parser.d.ts +4 -3
- package/dist/src/faf-core/parsers/agents-parser.js +4 -3
- package/dist/src/faf-core/parsers/agents-parser.js.map +1 -1
- package/dist/src/faf-core/parsers/conductor-parser.d.ts +1 -1
- package/dist/src/faf-core/parsers/conductor-parser.js +1 -1
- package/dist/src/faf-core/parsers/cursorrules-parser.d.ts +4 -3
- package/dist/src/faf-core/parsers/cursorrules-parser.js +4 -3
- package/dist/src/faf-core/parsers/cursorrules-parser.js.map +1 -1
- package/dist/src/faf-core/parsers/faf-git-generator.d.ts +1 -1
- package/dist/src/faf-core/parsers/faf-git-generator.js +6 -5
- package/dist/src/faf-core/parsers/faf-git-generator.js.map +1 -1
- package/dist/src/faf-core/parsers/gemini-parser.d.ts +4 -3
- package/dist/src/faf-core/parsers/gemini-parser.js +4 -3
- package/dist/src/faf-core/parsers/gemini-parser.js.map +1 -1
- package/dist/src/faf-core/parsers/github-extractor.d.ts +1 -1
- package/dist/src/faf-core/parsers/github-extractor.js +1 -1
- package/dist/src/faf-core/parsers/slot-counter.d.ts +1 -1
- package/dist/src/faf-core/parsers/slot-counter.js +1 -1
- package/dist/src/handlers/engine-adapter.js +5 -4
- package/dist/src/handlers/engine-adapter.js.map +1 -1
- package/dist/src/handlers/tools.d.ts +2 -2
- package/dist/src/handlers/tools.js +102 -132
- package/dist/src/handlers/tools.js.map +1 -1
- package/dist/src/server.js +1 -1
- package/dist/src/server.js.map +1 -1
- package/dist/src/utils/faf-cli-bridge.d.ts +12 -8
- package/dist/src/utils/faf-cli-bridge.js +12 -8
- package/dist/src/utils/faf-cli-bridge.js.map +1 -1
- package/package.json +3 -3
- package/project.faf +5 -5
- package/skills/faf-ide/SKILL.md +1 -1
- package/dist/src/faf-core/commands/bi-sync.d.ts +0 -29
- package/dist/src/faf-core/commands/bi-sync.js.map +0 -1
|
@@ -38,7 +38,6 @@ const fileHandler_1 = require("./fileHandler");
|
|
|
38
38
|
const fs = __importStar(require("fs"));
|
|
39
39
|
const os = __importStar(require("os"));
|
|
40
40
|
const pathModule = __importStar(require("path"));
|
|
41
|
-
const fuzzy_detector_1 = require("../utils/fuzzy-detector");
|
|
42
41
|
const faf_file_finder_js_1 = require("../utils/faf-file-finder.js");
|
|
43
42
|
const safe_path_1 = require("../utils/safe-path");
|
|
44
43
|
const version_1 = require("../version");
|
|
@@ -49,12 +48,12 @@ const path_resolver_1 = require("../utils/path-resolver");
|
|
|
49
48
|
// scoring or the tier ladder here — that's exactly the drift v2.1.0 set out
|
|
50
49
|
// to kill across the surface; v2.1.1 closes the loop on the active handler.
|
|
51
50
|
//
|
|
52
|
-
// Imported via ../utils/faf-cli-bridge.js — a
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
51
|
+
// Imported via ../utils/faf-cli-bridge.js — a one-file re-export that pins
|
|
52
|
+
// the relative dist path. It began as a workaround for faf-cli 6.7.1's `bun`
|
|
53
|
+
// exports condition (pointed at a non-shipped src/); 6.8.0 dropped it and
|
|
54
|
+
// 7.12.0 exports only `types`/`default`. Node and Bun load the same compiled
|
|
55
|
+
// module through the bridge, which stays for the CJS-to-ESM load and
|
|
56
|
+
// bundledFafCliVersion()'s path-walk. See the bridge header for the rationale.
|
|
58
57
|
const faf_cli_bridge_js_1 = require("../utils/faf-cli-bridge.js");
|
|
59
58
|
const turbocat_bridge_js_1 = require("../faf-core/extract/turbocat-bridge.js");
|
|
60
59
|
/**
|
|
@@ -66,8 +65,8 @@ const turbocat_bridge_js_1 = require("../faf-core/extract/turbocat-bridge.js");
|
|
|
66
65
|
* the 40%-MIN rule means one weak tool on the surface caps the whole server.
|
|
67
66
|
*
|
|
68
67
|
* Spine mirrors claude-faf-mcp's proven-A Core; the interop quad
|
|
69
|
-
* (
|
|
70
|
-
* the Cursor / IDE multi-format
|
|
68
|
+
* (faf_claude + faf_agents/faf_cursor/faf_gemini) is this edition's identity —
|
|
69
|
+
* the Cursor / IDE multi-format write — where CFM carries memory tools instead.
|
|
71
70
|
* See PLANET-FAF/strategy/claude-faf-mcp-core-tier-glama-a-2026-06-17.md.
|
|
72
71
|
*/
|
|
73
72
|
const CORE_TOOLS = new Set([
|
|
@@ -75,7 +74,7 @@ const CORE_TOOLS = new Set([
|
|
|
75
74
|
'faf_init', 'faf_auto', 'faf_go', 'faf_score', 'faf_doctor',
|
|
76
75
|
'faf_sync', 'faf_context', 'faf_trust', 'faf_about',
|
|
77
76
|
// IDE-edition interop — the differentiator
|
|
78
|
-
'
|
|
77
|
+
'faf_claude', 'faf_agents', 'faf_cursor', 'faf_gemini',
|
|
79
78
|
// Craft-grade utility
|
|
80
79
|
'faf_check', 'faf_git',
|
|
81
80
|
]);
|
|
@@ -206,7 +205,7 @@ class FafToolHandler {
|
|
|
206
205
|
},
|
|
207
206
|
{
|
|
208
207
|
name: 'faf_sync',
|
|
209
|
-
description: 'Reconcile project.faf with what the repo manifests say now (package.json name, description, framework dependencies). Dry-run by default: reports the fields that would change. Pass apply:true to write them into project.faf. Does not touch CLAUDE.md — use
|
|
208
|
+
description: 'Reconcile project.faf with what the repo manifests say now (package.json name, description, framework dependencies). Dry-run by default: reports the fields that would change. Pass apply:true to write them into project.faf. Does not touch CLAUDE.md — use faf_claude for CLAUDE.md, AGENTS.md, .cursorrules and GEMINI.md.',
|
|
210
209
|
annotations: {
|
|
211
210
|
title: 'Reconcile .faf with repo manifests',
|
|
212
211
|
readOnlyHint: false,
|
|
@@ -223,10 +222,10 @@ class FafToolHandler {
|
|
|
223
222
|
}
|
|
224
223
|
},
|
|
225
224
|
{
|
|
226
|
-
name: '
|
|
227
|
-
description: 'Write CLAUDE.md from project.faf (one direction: .faf → CLAUDE.md) and, with the format flags or all, also AGENTS.md, .cursorrules and GEMINI.md. Content outside the faf-managed block is preserved. Returns the files written. Use this to keep every AI tool\'s context file current from one source.',
|
|
225
|
+
name: 'faf_claude',
|
|
226
|
+
description: 'Write CLAUDE.md from project.faf (one direction: .faf → CLAUDE.md) and, with the format flags or all, also AGENTS.md, .cursorrules and GEMINI.md. Content outside the faf-managed block is preserved. Returns the files written. Use this to keep every AI tool\'s context file current from one source. (Named faf_bi_sync before 3.0.1; that name still works.)',
|
|
228
227
|
annotations: {
|
|
229
|
-
title: '
|
|
228
|
+
title: 'Write CLAUDE.md and IDE formats from .faf',
|
|
230
229
|
readOnlyHint: false,
|
|
231
230
|
destructiveHint: false,
|
|
232
231
|
openWorldHint: false
|
|
@@ -234,10 +233,10 @@ class FafToolHandler {
|
|
|
234
233
|
inputSchema: {
|
|
235
234
|
type: 'object',
|
|
236
235
|
properties: {
|
|
237
|
-
agents: { type: 'boolean', description: 'Also
|
|
238
|
-
cursor: { type: 'boolean', description: 'Also
|
|
239
|
-
gemini: { type: 'boolean', description: 'Also
|
|
240
|
-
all: { type: 'boolean', description: '
|
|
236
|
+
agents: { type: 'boolean', description: 'Also write AGENTS.md (OpenAI/Codex format)' },
|
|
237
|
+
cursor: { type: 'boolean', description: 'Also write .cursorrules (Cursor IDE format)' },
|
|
238
|
+
gemini: { type: 'boolean', description: 'Also write GEMINI.md (Google Gemini format)' },
|
|
239
|
+
all: { type: 'boolean', description: 'Write ALL formats: CLAUDE.md + AGENTS.md + .cursorrules + GEMINI.md' },
|
|
241
240
|
path: { type: 'string', description: 'Project path. Sets session context for subsequent calls.' }
|
|
242
241
|
},
|
|
243
242
|
additionalProperties: false
|
|
@@ -472,7 +471,7 @@ class FafToolHandler {
|
|
|
472
471
|
},
|
|
473
472
|
{
|
|
474
473
|
name: 'faf_auto',
|
|
475
|
-
description: 'Run the full setup pipeline in one call — init, stack detection, sync,
|
|
474
|
+
description: 'Run the full setup pipeline in one call — init, stack detection, sync, CLAUDE.md, and score — taking a project from no context to a complete project.faf. Returns the final AI-readiness score and what was created. Use this as the fast path on a fresh project; use the individual tools when you need finer control.',
|
|
476
475
|
annotations: {
|
|
477
476
|
title: 'Auto-detect Context',
|
|
478
477
|
readOnlyHint: false,
|
|
@@ -492,7 +491,7 @@ class FafToolHandler {
|
|
|
492
491
|
},
|
|
493
492
|
{
|
|
494
493
|
name: 'faf_dna',
|
|
495
|
-
description: 'Show your FAF DNA journey
|
|
494
|
+
description: 'Show your FAF DNA journey — the score evolution of this project.faf from birth to today (e.g. 22% → 85% → 100%)',
|
|
496
495
|
annotations: {
|
|
497
496
|
title: 'View Project DNA',
|
|
498
497
|
readOnlyHint: true,
|
|
@@ -560,11 +559,11 @@ class FafToolHandler {
|
|
|
560
559
|
}
|
|
561
560
|
},
|
|
562
561
|
// ============================================================================
|
|
563
|
-
//
|
|
562
|
+
// INTEROP TOOLS — landed in faf-mcp 2.0.0 (The Interop MCP for Context); ported from faf-cli 4.5.0 via claude-faf-mcp 4.5.0
|
|
564
563
|
// ============================================================================
|
|
565
564
|
{
|
|
566
565
|
name: 'faf_agents',
|
|
567
|
-
description: 'Import
|
|
566
|
+
description: 'Import AGENTS.md (the OpenAI/Codex convention) into project.faf, or write it from project.faf. Returns the merged or written result for the chosen action. Use this to keep a Codex/OpenAI-style AGENTS.md and your .faf in agreement from one source.',
|
|
568
567
|
annotations: {
|
|
569
568
|
title: 'Sync AGENTS.md',
|
|
570
569
|
readOnlyHint: false,
|
|
@@ -574,7 +573,7 @@ class FafToolHandler {
|
|
|
574
573
|
inputSchema: {
|
|
575
574
|
type: 'object',
|
|
576
575
|
properties: {
|
|
577
|
-
action: { type: 'string', enum: ['import', 'export', 'sync'], description: 'Action: import (AGENTS.md -> .faf), export (.faf -> AGENTS.md), sync (
|
|
576
|
+
action: { type: 'string', enum: ['import', 'export', 'sync'], description: 'Action: import (AGENTS.md -> .faf; merge:true writes it into project.faf), export (.faf -> AGENTS.md), sync (re-writes AGENTS.md from .faf; export with force)' },
|
|
578
577
|
force: { type: 'boolean', description: 'Force overwrite existing files' },
|
|
579
578
|
merge: { type: 'boolean', description: 'Merge imported data with existing .faf instead of replacing' },
|
|
580
579
|
path: { type: 'string', description: 'Project path. Sets session context for subsequent calls.' }
|
|
@@ -585,7 +584,7 @@ class FafToolHandler {
|
|
|
585
584
|
},
|
|
586
585
|
{
|
|
587
586
|
name: 'faf_cursor',
|
|
588
|
-
description: 'Import
|
|
587
|
+
description: 'Import .cursorrules (the Cursor IDE convention) into project.faf, or write it from project.faf. Returns the merged or written result for the chosen action. Use this to keep Cursor rules and your .faf in agreement from one source.',
|
|
589
588
|
annotations: {
|
|
590
589
|
title: 'Sync .cursorrules',
|
|
591
590
|
readOnlyHint: false,
|
|
@@ -595,7 +594,7 @@ class FafToolHandler {
|
|
|
595
594
|
inputSchema: {
|
|
596
595
|
type: 'object',
|
|
597
596
|
properties: {
|
|
598
|
-
action: { type: 'string', enum: ['import', 'export', 'sync'], description: 'Action: import (.cursorrules -> .faf), export (.faf -> .cursorrules), sync (
|
|
597
|
+
action: { type: 'string', enum: ['import', 'export', 'sync'], description: 'Action: import (.cursorrules -> .faf; merge:true writes it into project.faf), export (.faf -> .cursorrules), sync (re-writes .cursorrules from .faf; export with force)' },
|
|
599
598
|
force: { type: 'boolean', description: 'Force overwrite existing files' },
|
|
600
599
|
merge: { type: 'boolean', description: 'Merge imported data with existing .faf instead of replacing' },
|
|
601
600
|
path: { type: 'string', description: 'Project path. Sets session context for subsequent calls.' }
|
|
@@ -606,7 +605,7 @@ class FafToolHandler {
|
|
|
606
605
|
},
|
|
607
606
|
{
|
|
608
607
|
name: 'faf_gemini',
|
|
609
|
-
description: 'Import
|
|
608
|
+
description: 'Import GEMINI.md (the Google Gemini CLI convention) into project.faf, or write it from project.faf. Returns the merged or written result for the chosen action. Use this to keep a Gemini context file and your .faf in agreement from one source.',
|
|
610
609
|
annotations: {
|
|
611
610
|
title: 'Sync GEMINI.md',
|
|
612
611
|
readOnlyHint: false,
|
|
@@ -616,7 +615,7 @@ class FafToolHandler {
|
|
|
616
615
|
inputSchema: {
|
|
617
616
|
type: 'object',
|
|
618
617
|
properties: {
|
|
619
|
-
action: { type: 'string', enum: ['import', 'export', 'sync'], description: 'Action: import (GEMINI.md -> .faf), export (.faf -> GEMINI.md), sync (
|
|
618
|
+
action: { type: 'string', enum: ['import', 'export', 'sync'], description: 'Action: import (GEMINI.md -> .faf; merge:true writes it into project.faf), export (.faf -> GEMINI.md), sync (re-writes GEMINI.md from .faf; export with force)' },
|
|
620
619
|
force: { type: 'boolean', description: 'Force overwrite existing files' },
|
|
621
620
|
merge: { type: 'boolean', description: 'Merge imported data with existing .faf instead of replacing' },
|
|
622
621
|
path: { type: 'string', description: 'Project path. Sets session context for subsequent calls.' }
|
|
@@ -648,7 +647,7 @@ class FafToolHandler {
|
|
|
648
647
|
},
|
|
649
648
|
{
|
|
650
649
|
name: 'faf_git',
|
|
651
|
-
description: '
|
|
650
|
+
description: 'Author a project.faf from any public GitHub repository URL — fetches the repo and extracts its stack and context. Returns the authored .faf. Use this to bootstrap context for a project you have the URL for but not cloned locally.',
|
|
652
651
|
annotations: {
|
|
653
652
|
title: 'Extract from GitHub',
|
|
654
653
|
readOnlyHint: false,
|
|
@@ -659,7 +658,7 @@ class FafToolHandler {
|
|
|
659
658
|
type: 'object',
|
|
660
659
|
properties: {
|
|
661
660
|
url: { type: 'string', description: 'GitHub repository URL (e.g., https://github.com/owner/repo or owner/repo)' },
|
|
662
|
-
path: { type: 'string', description: 'Output directory for
|
|
661
|
+
path: { type: 'string', description: 'Output directory for the authored project.faf. If omitted, returns content without writing.' }
|
|
663
662
|
},
|
|
664
663
|
required: ['url'],
|
|
665
664
|
additionalProperties: false
|
|
@@ -689,8 +688,9 @@ class FafToolHandler {
|
|
|
689
688
|
return await this.handleFafTrust(args);
|
|
690
689
|
case 'faf_sync':
|
|
691
690
|
return await this.handleFafSync(args);
|
|
692
|
-
case 'faf_bi_sync':
|
|
693
|
-
|
|
691
|
+
case 'faf_bi_sync': // pre-3.0.1 name: still callable, never listed
|
|
692
|
+
case 'faf_claude':
|
|
693
|
+
return await this.handleFafClaude(args);
|
|
694
694
|
case 'faf_clear':
|
|
695
695
|
return await this.handleFafClear(args);
|
|
696
696
|
case 'faf_debug':
|
|
@@ -736,7 +736,7 @@ class FafToolHandler {
|
|
|
736
736
|
return await this.handleFafQuick(args);
|
|
737
737
|
case 'faf_doctor':
|
|
738
738
|
return await this.handleFafDoctor(args);
|
|
739
|
-
//
|
|
739
|
+
// Interop tools (faf-mcp 2.0.0; ported from faf-cli 4.5.0 via claude-faf-mcp 4.5.0)
|
|
740
740
|
case 'faf_agents':
|
|
741
741
|
return await this.handleFafAgents(args);
|
|
742
742
|
case 'faf_cursor':
|
|
@@ -769,7 +769,7 @@ class FafToolHandler {
|
|
|
769
769
|
return {
|
|
770
770
|
content: [{
|
|
771
771
|
type: 'text',
|
|
772
|
-
text: `🤖
|
|
772
|
+
text: `🤖 FAF Project Status:\n\n❌ No FAF file found in ${cwd}\n💡 Run faf_init to create project.faf`
|
|
773
773
|
}]
|
|
774
774
|
};
|
|
775
775
|
}
|
|
@@ -778,7 +778,7 @@ class FafToolHandler {
|
|
|
778
778
|
return {
|
|
779
779
|
content: [{
|
|
780
780
|
type: 'text',
|
|
781
|
-
text: `🤖
|
|
781
|
+
text: `🤖 FAF Project Status:\n\n✅ ${fafResult.filename} found in ${cwd}\n\nContent preview:\n${lines.join('\n')}`
|
|
782
782
|
}]
|
|
783
783
|
};
|
|
784
784
|
}
|
|
@@ -786,7 +786,7 @@ class FafToolHandler {
|
|
|
786
786
|
return {
|
|
787
787
|
content: [{
|
|
788
788
|
type: 'text',
|
|
789
|
-
text: `🤖
|
|
789
|
+
text: `🤖 FAF Project Status:\n\n❌ Error: ${error.message}`
|
|
790
790
|
}],
|
|
791
791
|
isError: true
|
|
792
792
|
};
|
|
@@ -849,7 +849,7 @@ class FafToolHandler {
|
|
|
849
849
|
text: `FAF SCORE: 0/100 (0%) ○ INVALID\n\n` +
|
|
850
850
|
`\`${fafPath}\` couldn't be parsed as a valid .faf YAML:\n` +
|
|
851
851
|
` ${error?.message ?? String(error)}\n\n` +
|
|
852
|
-
`Re-run \`faf_init\` to
|
|
852
|
+
`Re-run \`faf_init\` with force: true to write a fresh, valid file.`,
|
|
853
853
|
},
|
|
854
854
|
],
|
|
855
855
|
isError: true,
|
|
@@ -898,13 +898,19 @@ class FafToolHandler {
|
|
|
898
898
|
};
|
|
899
899
|
}
|
|
900
900
|
async handleFafInit(args) {
|
|
901
|
-
//
|
|
901
|
+
// faf_init is `faf init`: the same exported faf-cli steps the CLI command
|
|
902
|
+
// runs (assembleFreshFaf detects the folder → writeFaf → readFafRaw →
|
|
903
|
+
// scoreFafYaml), on the folder the path resolves to. Until 3.0.1 this
|
|
904
|
+
// wrote its own legacy template (no format version, `project:` as a
|
|
905
|
+
// plain string) that scored 0% whatever the folder held, failed faf_trust and
|
|
906
|
+
// crashed faf_go. Two steps of `faf init` are not exported by faf-cli
|
|
907
|
+
// 7.12 and are not repeated here: the home/root refusal and the
|
|
908
|
+
// .faf-dna birth record (faf_dna writes that on its first call).
|
|
902
909
|
try {
|
|
903
|
-
//
|
|
910
|
+
// Path resolution unchanged (supports "my-app", "~/Projects/my-app", "/full/path")
|
|
904
911
|
const userInput = args?.path;
|
|
905
912
|
const resolution = (0, path_resolver_1.resolveProjectPath)(userInput);
|
|
906
913
|
const targetDir = resolution.projectPath;
|
|
907
|
-
const projectName = resolution.projectName;
|
|
908
914
|
const fafPath = resolution.fafFilePath;
|
|
909
915
|
// Ensure project directory exists
|
|
910
916
|
if (!fs.existsSync(targetDir)) {
|
|
@@ -916,57 +922,16 @@ class FafToolHandler {
|
|
|
916
922
|
return {
|
|
917
923
|
content: [{
|
|
918
924
|
type: 'text',
|
|
919
|
-
text: `🚀
|
|
925
|
+
text: `🚀 FAF Initialization:\n\n⚠️ ${existingFaf.filename} already exists in ${targetDir}\n💡 Use force: true to overwrite`
|
|
920
926
|
}]
|
|
921
927
|
};
|
|
922
928
|
}
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
let projectData = {
|
|
930
|
-
project: projectName,
|
|
931
|
-
project_type: projectType,
|
|
932
|
-
description: projectDescription,
|
|
933
|
-
generated: new Date().toISOString(),
|
|
934
|
-
version: version_1.VERSION
|
|
935
|
-
};
|
|
936
|
-
// Apply Intel-Friday: Auto-fill Chrome Extension slots for 90%+ score!
|
|
937
|
-
if (chromeDetection.detected) {
|
|
938
|
-
projectData = (0, fuzzy_detector_1.applyIntelFriday)(projectData);
|
|
939
|
-
}
|
|
940
|
-
// Create enhanced .faf content
|
|
941
|
-
const fafContent = `# FAF - Foundational AI Context
|
|
942
|
-
project: ${projectData.project}
|
|
943
|
-
type: ${projectData.project_type}${chromeDetection.detected ? ' 🎯' : ''}
|
|
944
|
-
context: I⚡🍊
|
|
945
|
-
generated: ${projectData.generated}
|
|
946
|
-
version: ${projectData.version}
|
|
947
|
-
${chromeDetection.corrected ? `# Auto-corrected: "${args?.description}" → "${chromeDetection.corrected}"` : ''}
|
|
948
|
-
|
|
949
|
-
# The Formula
|
|
950
|
-
human_input: Your project files
|
|
951
|
-
multiplier: FAF Context
|
|
952
|
-
output: Championship Performance
|
|
953
|
-
|
|
954
|
-
# Quick Context
|
|
955
|
-
working_directory: ${targetDir}
|
|
956
|
-
initialized_by: faf-mcp${projectData._friday_feature ? `\nfriday_feature: ${projectData._friday_feature}` : ''}
|
|
957
|
-
vitamin_context: true
|
|
958
|
-
faffless: true
|
|
959
|
-
|
|
960
|
-
${chromeDetection.detected ? `# Chrome Extension Auto-Fill (90%+ Score!)
|
|
961
|
-
runtime: ${projectData.runtime}
|
|
962
|
-
hosting: ${projectData.hosting}
|
|
963
|
-
api_type: ${projectData.api_type}
|
|
964
|
-
backend: ${projectData.backend}
|
|
965
|
-
database: ${projectData.database}
|
|
966
|
-
build: ${projectData.build}
|
|
967
|
-
package_manager: ${projectData.package_manager}` : ''}
|
|
968
|
-
`;
|
|
969
|
-
fs.writeFileSync(fafPath, fafContent);
|
|
929
|
+
const { assembleFreshFaf, writeFaf, readFafRaw, scoreFafYaml } = await faf_cli_bridge_js_1.fafCli;
|
|
930
|
+
writeFaf(fafPath, assembleFreshFaf(targetDir));
|
|
931
|
+
const score = scoreFafYaml(readFafRaw(fafPath));
|
|
932
|
+
// Like `cd` + `faf init`: the new project becomes the current one, so the
|
|
933
|
+
// next steps printed below (faf_score, faf_claude, faf_go) act on it.
|
|
934
|
+
this.engineAdapter.setWorkingDirectory(targetDir);
|
|
970
935
|
// Pomelli-style success confirmation with path resolution info
|
|
971
936
|
const pathConfirmation = (0, path_resolver_1.formatPathConfirmation)(resolution);
|
|
972
937
|
const sourceExplanation = resolution.source === 'user-name'
|
|
@@ -975,7 +940,7 @@ package_manager: ${projectData.package_manager}` : ''}
|
|
|
975
940
|
return {
|
|
976
941
|
content: [{
|
|
977
942
|
type: 'text',
|
|
978
|
-
text: `🚀
|
|
943
|
+
text: `🚀 FAF Initialization:\n\n✅ Created project.faf\n📊 ${score.score}/100 (${score.populated}/${score.active} slots populated) — ${score.tier.name}\n\n${pathConfirmation}${sourceExplanation}\n\n🍊 Vitamin Context activated!\n⚡ FAFFLESS AI ready!\n\n🏁 Next steps:\n • Run faf_score for AI-readiness score\n • Run faf_claude to write CLAUDE.md\n • Run faf_go to fill the gaps`
|
|
979
944
|
}]
|
|
980
945
|
};
|
|
981
946
|
}
|
|
@@ -983,7 +948,7 @@ package_manager: ${projectData.package_manager}` : ''}
|
|
|
983
948
|
return {
|
|
984
949
|
content: [{
|
|
985
950
|
type: 'text',
|
|
986
|
-
text: `🚀
|
|
951
|
+
text: `🚀 FAF Initialization:\n\n❌ Error: ${error.message}`
|
|
987
952
|
}],
|
|
988
953
|
isError: true
|
|
989
954
|
};
|
|
@@ -1011,7 +976,7 @@ package_manager: ${projectData.package_manager}` : ''}
|
|
|
1011
976
|
return {
|
|
1012
977
|
content: [{
|
|
1013
978
|
type: 'text',
|
|
1014
|
-
text: `🔒
|
|
979
|
+
text: `🔒 FAF Trust Validation:\n\n❌ No .faf found in ${cwd}\n💡 Run faf_init to create one — then faf_trust reports real trust metrics.`
|
|
1015
980
|
}]
|
|
1016
981
|
};
|
|
1017
982
|
}
|
|
@@ -1025,7 +990,7 @@ package_manager: ${projectData.package_manager}` : ''}
|
|
|
1025
990
|
return {
|
|
1026
991
|
content: [{
|
|
1027
992
|
type: 'text',
|
|
1028
|
-
text: `🔒
|
|
993
|
+
text: `🔒 FAF Trust Validation:\n\n❌ Could not read ${fafPath}: ${error?.message ?? String(error)}`
|
|
1029
994
|
}],
|
|
1030
995
|
isError: true
|
|
1031
996
|
};
|
|
@@ -1045,7 +1010,7 @@ package_manager: ${projectData.package_manager}` : ''}
|
|
|
1045
1010
|
return {
|
|
1046
1011
|
content: [{
|
|
1047
1012
|
type: 'text',
|
|
1048
|
-
text: `🔒
|
|
1013
|
+
text: `🔒 FAF Trust Validation:\n\n${output}`
|
|
1049
1014
|
}],
|
|
1050
1015
|
isError: !validation.valid
|
|
1051
1016
|
};
|
|
@@ -1062,7 +1027,7 @@ package_manager: ${projectData.package_manager}` : ''}
|
|
|
1062
1027
|
return {
|
|
1063
1028
|
content: [{
|
|
1064
1029
|
type: 'text',
|
|
1065
|
-
text: `🔄
|
|
1030
|
+
text: `🔄 FAF Sync:\n\nFailed to sync: ${result.error}`
|
|
1066
1031
|
}],
|
|
1067
1032
|
isError: true
|
|
1068
1033
|
};
|
|
@@ -1073,39 +1038,39 @@ package_manager: ${projectData.package_manager}` : ''}
|
|
|
1073
1038
|
return {
|
|
1074
1039
|
content: [{
|
|
1075
1040
|
type: 'text',
|
|
1076
|
-
text: `🔄
|
|
1041
|
+
text: `🔄 FAF Sync:\n\n${output}`
|
|
1077
1042
|
}]
|
|
1078
1043
|
};
|
|
1079
1044
|
}
|
|
1080
|
-
async
|
|
1045
|
+
async handleFafClaude(args) {
|
|
1081
1046
|
// Set project context if path provided
|
|
1082
1047
|
if (args?.path) {
|
|
1083
1048
|
this.getProjectPath(args.path);
|
|
1084
1049
|
}
|
|
1085
1050
|
// auto / watch / force used to be declared here too; none of them was
|
|
1086
|
-
// ever read by
|
|
1087
|
-
const
|
|
1051
|
+
// ever read by the command, so the schema no longer promises them.
|
|
1052
|
+
const claudeArgs = [];
|
|
1088
1053
|
// v3.0 fix: the tool's own schema advertises agents/cursor/gemini/all,
|
|
1089
|
-
// but they were never forwarded to engine
|
|
1090
|
-
//
|
|
1054
|
+
// but before 3.0 they were never forwarded to the engine adapter —
|
|
1055
|
+
// the tool silently ignored them and only ever wrote CLAUDE.md.
|
|
1091
1056
|
if (args?.agents) {
|
|
1092
|
-
|
|
1057
|
+
claudeArgs.push('--agents');
|
|
1093
1058
|
}
|
|
1094
1059
|
if (args?.cursor) {
|
|
1095
|
-
|
|
1060
|
+
claudeArgs.push('--cursor');
|
|
1096
1061
|
}
|
|
1097
1062
|
if (args?.gemini) {
|
|
1098
|
-
|
|
1063
|
+
claudeArgs.push('--gemini');
|
|
1099
1064
|
}
|
|
1100
1065
|
if (args?.all) {
|
|
1101
|
-
|
|
1066
|
+
claudeArgs.push('--all');
|
|
1102
1067
|
}
|
|
1103
|
-
const result = await this.engineAdapter.callEngine('
|
|
1068
|
+
const result = await this.engineAdapter.callEngine('claude', claudeArgs);
|
|
1104
1069
|
if (!result.success) {
|
|
1105
1070
|
return {
|
|
1106
1071
|
content: [{
|
|
1107
1072
|
type: 'text',
|
|
1108
|
-
text: `🔗
|
|
1073
|
+
text: `🔗 FAF → CLAUDE.md:\n\nCould not write CLAUDE.md: ${result.error}`
|
|
1109
1074
|
}],
|
|
1110
1075
|
isError: true
|
|
1111
1076
|
};
|
|
@@ -1116,7 +1081,7 @@ package_manager: ${projectData.package_manager}` : ''}
|
|
|
1116
1081
|
return {
|
|
1117
1082
|
content: [{
|
|
1118
1083
|
type: 'text',
|
|
1119
|
-
text: `🔗
|
|
1084
|
+
text: `🔗 FAF → CLAUDE.md:\n\n${output}`
|
|
1120
1085
|
}]
|
|
1121
1086
|
};
|
|
1122
1087
|
}
|
|
@@ -1159,7 +1124,7 @@ package_manager: ${projectData.package_manager}` : ''}
|
|
|
1159
1124
|
return {
|
|
1160
1125
|
content: [{
|
|
1161
1126
|
type: 'text',
|
|
1162
|
-
text: `🧹
|
|
1127
|
+
text: `🧹 FAF Clear:\n\n${lines.join('\n')}`
|
|
1163
1128
|
}]
|
|
1164
1129
|
};
|
|
1165
1130
|
}
|
|
@@ -1188,7 +1153,7 @@ WHAT IS .FAF?
|
|
|
1188
1153
|
• The dot (.) means it's a file format!
|
|
1189
1154
|
|
|
1190
1155
|
🧡 Trust: Context verified
|
|
1191
|
-
⚡️ Speed:
|
|
1156
|
+
⚡️ Speed: Authored in <29ms
|
|
1192
1157
|
SPEEDY AI you can TRUST!
|
|
1193
1158
|
|
|
1194
1159
|
Version ${packageInfo.version}
|
|
@@ -1199,10 +1164,10 @@ Just like JPEG makes images universal,
|
|
|
1199
1164
|
HOW IT WORKS:
|
|
1200
1165
|
1. Drop a file or paste the path
|
|
1201
1166
|
2. Create .faf (Foundational AI-context Format)
|
|
1202
|
-
3.
|
|
1167
|
+
3. Ask your AI to run faf_claude
|
|
1203
1168
|
4. You're done⚡
|
|
1204
1169
|
|
|
1205
|
-
🩵 You just made
|
|
1170
|
+
🩵 You just made your AI happy
|
|
1206
1171
|
🧡⚡️ SPEEDY AI you can TRUST!`;
|
|
1207
1172
|
return {
|
|
1208
1173
|
content: [{
|
|
@@ -1221,7 +1186,7 @@ WHY: Just like JPEG makes images viewable everywhere,
|
|
|
1221
1186
|
.faf makes projects understandable by AI.
|
|
1222
1187
|
|
|
1223
1188
|
HOW: Run 'faf' on any project to create one.
|
|
1224
|
-
Run 'faf_score' to check AI-readiness (target:
|
|
1189
|
+
Run 'faf_score' to check AI-readiness (target: 100%).
|
|
1225
1190
|
|
|
1226
1191
|
REMEMBER: Always use ".faf" with the dot - it's a FORMAT!
|
|
1227
1192
|
|
|
@@ -1283,7 +1248,7 @@ ${debugInfo.permissions.writeError ? ` Error: ${debugInfo.permissions.writeErr
|
|
|
1283
1248
|
return {
|
|
1284
1249
|
content: [{
|
|
1285
1250
|
type: 'text',
|
|
1286
|
-
text: `🔍
|
|
1251
|
+
text: `🔍 faf-mcp Debug Failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1287
1252
|
}],
|
|
1288
1253
|
isError: true
|
|
1289
1254
|
};
|
|
@@ -1335,7 +1300,6 @@ All work: \`faf init\`, \`faf init new\`, \`faf init --new\`, \`faf init -new\`
|
|
|
1335
1300
|
**Extensions:**
|
|
1336
1301
|
- \`new\` - force overwrite existing
|
|
1337
1302
|
- \`full\` - detailed output
|
|
1338
|
-
- \`bi\` - bi-directional sync
|
|
1339
1303
|
|
|
1340
1304
|
## UX Rules
|
|
1341
1305
|
1. **Don't offer option menus** - just solve it
|
|
@@ -1495,7 +1459,7 @@ All work: \`faf init\`, \`faf init new\`, \`faf init --new\`, \`faf init -new\`
|
|
|
1495
1459
|
}
|
|
1496
1460
|
}
|
|
1497
1461
|
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
1498
|
-
//
|
|
1462
|
+
// Human Context Tools (parity with faf-cli v3.2.0)
|
|
1499
1463
|
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
1500
1464
|
async handleFafReadme(args) {
|
|
1501
1465
|
try {
|
|
@@ -1722,7 +1686,7 @@ All work: \`faf init\`, \`faf init new\`, \`faf init --new\`, \`faf init -new\`
|
|
|
1722
1686
|
}
|
|
1723
1687
|
// Default: show quality report
|
|
1724
1688
|
const icons = {
|
|
1725
|
-
empty: '⬜', generic: '
|
|
1689
|
+
empty: '⬜', generic: '◻️', good: '◼️', excellent: '💎'
|
|
1726
1690
|
};
|
|
1727
1691
|
let output = `🔍 FAF Human Context Quality\n\n`;
|
|
1728
1692
|
for (const field of fields) {
|
|
@@ -1909,7 +1873,7 @@ All work: \`faf init\`, \`faf init new\`, \`faf init --new\`, \`faf init -new\`
|
|
|
1909
1873
|
text: JSON.stringify({
|
|
1910
1874
|
complete: true,
|
|
1911
1875
|
score: 100,
|
|
1912
|
-
message: '
|
|
1876
|
+
message: '✪ GOLD CODE ACHIEVED! Your project has 100% AI-Readiness.',
|
|
1913
1877
|
context: 'faf_go'
|
|
1914
1878
|
}, null, 2)
|
|
1915
1879
|
}]
|
|
@@ -2033,19 +1997,25 @@ All work: \`faf init\`, \`faf init new\`, \`faf init --new\`, \`faf init -new\`
|
|
|
2033
1997
|
output += `⏱️ Completed in ${elapsed}s\n`;
|
|
2034
1998
|
output += `📊 Before: ${beforeScore}% | After: ${newScore}% ${deltaDisplay}\n`;
|
|
2035
1999
|
output += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n`;
|
|
2036
|
-
if (newScore >=
|
|
2037
|
-
output +=
|
|
2000
|
+
if (newScore >= 100) {
|
|
2001
|
+
output += `✪ TROPHY — 100% AI-Readiness. Your AI has complete context.\n`;
|
|
2002
|
+
}
|
|
2003
|
+
else if (newScore >= 99) {
|
|
2004
|
+
output += `★ Gold — 1% to Trophy. Run faf_go to finish.\n`;
|
|
2005
|
+
}
|
|
2006
|
+
else if (newScore >= 95) {
|
|
2007
|
+
output += `◆ Silver — ${100 - newScore}% to Trophy.\n`;
|
|
2038
2008
|
}
|
|
2039
2009
|
else if (newScore >= 85) {
|
|
2040
|
-
output +=
|
|
2010
|
+
output += `◇ Bronze — production ready. ${100 - newScore}% to Trophy.\n`;
|
|
2041
2011
|
}
|
|
2042
2012
|
else if (newScore >= 70) {
|
|
2043
|
-
output +=
|
|
2013
|
+
output += `● Green — solid foundation. Run faf_go to climb tiers.\n`;
|
|
2044
2014
|
}
|
|
2045
2015
|
else {
|
|
2046
2016
|
output += `🚀 Good start! Run faf_go for guided improvement.\n`;
|
|
2047
2017
|
}
|
|
2048
|
-
output += `\n💡 Next: faf_score | faf_go |
|
|
2018
|
+
output += `\n💡 Next: faf_score | faf_go | faf_claude`;
|
|
2049
2019
|
return { content: [{ type: 'text', text: output }] };
|
|
2050
2020
|
}
|
|
2051
2021
|
catch (error) {
|
|
@@ -2057,7 +2027,7 @@ All work: \`faf init\`, \`faf init new\`, \`faf init --new\`, \`faf init -new\`
|
|
|
2057
2027
|
}
|
|
2058
2028
|
/**
|
|
2059
2029
|
* faf_dna - Show your FAF DNA journey
|
|
2060
|
-
* Displays evolution from birth to
|
|
2030
|
+
* Displays the score evolution from birth to today (e.g. 22% → 85% → 100%)
|
|
2061
2031
|
*/
|
|
2062
2032
|
async handleFafDna(args) {
|
|
2063
2033
|
const cwd = this.getProjectPath(args?.path);
|
|
@@ -2171,7 +2141,7 @@ All work: \`faf init\`, \`faf init new\`, \`faf init --new\`, \`faf init -new\`
|
|
|
2171
2141
|
output += `\n🧬 MILESTONES\n`;
|
|
2172
2142
|
const milestoneIcons = {
|
|
2173
2143
|
birth: '🐣', first_save: '💾', doubled: '2️⃣', sync: '🔄',
|
|
2174
|
-
championship: '
|
|
2144
|
+
championship: '✪', elite: '⭐', peak: '🏔️', perfect: '💎'
|
|
2175
2145
|
};
|
|
2176
2146
|
for (const m of milestones) {
|
|
2177
2147
|
const icon = milestoneIcons[m.type] || '📍';
|
|
@@ -2220,7 +2190,7 @@ All work: \`faf init\`, \`faf init new\`, \`faf init --new\`, \`faf init -new\`
|
|
|
2220
2190
|
};
|
|
2221
2191
|
}
|
|
2222
2192
|
// Format human-readable output
|
|
2223
|
-
let output = `😽 TURBO-CAT™ Format Discovery
|
|
2193
|
+
let output = `😽 TURBO-CAT™ Format Discovery\n`;
|
|
2224
2194
|
output += `═══════════════════════════════════════════════════\n\n`;
|
|
2225
2195
|
output += `✅ Found ${analysis.discoveredFormats.length} formats in ${elapsed}ms!\n\n`;
|
|
2226
2196
|
output += `📋 Discovered Formats (A-Z):\n`;
|
|
@@ -2229,7 +2199,7 @@ All work: \`faf init\`, \`faf init new\`, \`faf init --new\`, \`faf init -new\`
|
|
|
2229
2199
|
output += ` ✅ ${format.fileName}\n`;
|
|
2230
2200
|
}
|
|
2231
2201
|
output += `\n💡 Stack Signature: ${analysis.stackSignature}\n`;
|
|
2232
|
-
output +=
|
|
2202
|
+
output += `🧠 Intelligence Score: ${analysis.totalIntelligenceScore}\n\n`;
|
|
2233
2203
|
if (Object.keys(analysis.slotFillRecommendations).length > 0) {
|
|
2234
2204
|
output += `📊 Recommended Slot Fills:\n`;
|
|
2235
2205
|
for (const [key, value] of Object.entries(analysis.slotFillRecommendations)) {
|
|
@@ -2438,7 +2408,7 @@ Use force: true to overwrite, or use faf_go / faf_human_add to modify.`
|
|
|
2438
2408
|
results.push({
|
|
2439
2409
|
status: 'error',
|
|
2440
2410
|
message: '.faf file is empty',
|
|
2441
|
-
fix: 'Run: faf_init with force option to
|
|
2411
|
+
fix: 'Run: faf_init with force option to rewrite it'
|
|
2442
2412
|
});
|
|
2443
2413
|
}
|
|
2444
2414
|
else {
|
|
@@ -2494,7 +2464,7 @@ Use force: true to overwrite, or use faf_go / faf_human_add to modify.`
|
|
|
2494
2464
|
results.push({
|
|
2495
2465
|
status: 'error',
|
|
2496
2466
|
message: '.faf file is corrupted or invalid YAML',
|
|
2497
|
-
fix: 'Run: faf_init with force option to
|
|
2467
|
+
fix: 'Run: faf_init with force option to rewrite it'
|
|
2498
2468
|
});
|
|
2499
2469
|
}
|
|
2500
2470
|
}
|
|
@@ -2504,13 +2474,13 @@ Use force: true to overwrite, or use faf_go / faf_human_add to modify.`
|
|
|
2504
2474
|
results.push({
|
|
2505
2475
|
status: 'warning',
|
|
2506
2476
|
message: 'No CLAUDE.md file',
|
|
2507
|
-
fix: 'Run: faf_auto or
|
|
2477
|
+
fix: 'Run: faf_auto or faf_claude to write CLAUDE.md'
|
|
2508
2478
|
});
|
|
2509
2479
|
}
|
|
2510
2480
|
else {
|
|
2511
2481
|
results.push({
|
|
2512
2482
|
status: 'ok',
|
|
2513
|
-
message: 'CLAUDE.md found
|
|
2483
|
+
message: 'CLAUDE.md found'
|
|
2514
2484
|
});
|
|
2515
2485
|
}
|
|
2516
2486
|
// Check 6: Project detection
|
|
@@ -2568,7 +2538,7 @@ Use force: true to overwrite, or use faf_go / faf_human_add to modify.`
|
|
|
2568
2538
|
}
|
|
2569
2539
|
output += `\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n`;
|
|
2570
2540
|
if (!hasErrors && !hasWarnings) {
|
|
2571
|
-
output +=
|
|
2541
|
+
output += `✅ Perfect health! Your FAF setup is championship-ready!`;
|
|
2572
2542
|
}
|
|
2573
2543
|
else if (!hasErrors) {
|
|
2574
2544
|
output += `🎯 Good health with minor improvements suggested.`;
|
|
@@ -2586,7 +2556,7 @@ Use force: true to overwrite, or use faf_go / faf_human_add to modify.`
|
|
|
2586
2556
|
}
|
|
2587
2557
|
}
|
|
2588
2558
|
// ============================================================================
|
|
2589
|
-
//
|
|
2559
|
+
// INTEROP HANDLERS (faf-mcp 2.0.0; ported from faf-cli 4.5.0 via claude-faf-mcp 4.5.0)
|
|
2590
2560
|
// ============================================================================
|
|
2591
2561
|
async handleFafAgents(args) {
|
|
2592
2562
|
const cwd = this.getProjectPath(args?.path);
|
|
@@ -2724,7 +2694,7 @@ Use force: true to overwrite, or use faf_go / faf_human_add to modify.`
|
|
|
2724
2694
|
let output = `GitHub Context:\n\n✅ ${data?.message || 'Done'}\n⏱️ ${result.duration}ms`;
|
|
2725
2695
|
// Include generated .faf content if no output path (preview mode)
|
|
2726
2696
|
if (!outputPath && data?.data?.fafContent) {
|
|
2727
|
-
output += `\n\n---
|
|
2697
|
+
output += `\n\n--- Authored project.faf ---\n${data.data.fafContent}`;
|
|
2728
2698
|
}
|
|
2729
2699
|
return {
|
|
2730
2700
|
content: [{ type: 'text', text: output }]
|