faf-mcp 2.1.1 → 2.1.3
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 +30 -1
- package/CLAUDE.md +3 -3
- package/README.md +8 -7
- package/dist/src/cli.js +2 -15
- package/dist/src/cli.js.map +1 -1
- package/dist/src/faf-core/commands/bi-sync.js +3 -2
- package/dist/src/faf-core/commands/bi-sync.js.map +1 -1
- package/dist/src/faf-core/compiler/faf-compiler.js +65 -6
- package/dist/src/faf-core/compiler/faf-compiler.js.map +1 -1
- package/dist/src/faf-core/inject.d.ts +19 -0
- package/dist/src/faf-core/inject.js +57 -0
- package/dist/src/faf-core/inject.js.map +1 -0
- package/dist/src/faf-core/parsers/agents-parser.js +3 -2
- package/dist/src/faf-core/parsers/agents-parser.js.map +1 -1
- package/dist/src/faf-core/parsers/cursorrules-parser.js +6 -2
- package/dist/src/faf-core/parsers/cursorrules-parser.js.map +1 -1
- package/dist/src/faf-core/parsers/gemini-parser.js +3 -2
- package/dist/src/faf-core/parsers/gemini-parser.js.map +1 -1
- package/dist/src/handlers/championship-tools.js +11 -11
- package/dist/src/handlers/championship-tools.js.map +1 -1
- package/dist/src/handlers/cloud-handler.js +1 -1
- package/dist/src/handlers/cloud-handler.js.map +1 -1
- package/dist/src/handlers/fileHandler.js +31 -22
- package/dist/src/handlers/fileHandler.js.map +1 -1
- package/dist/src/handlers/tools.js +105 -127
- package/dist/src/handlers/tools.js.map +1 -1
- package/dist/src/server.d.ts +2 -4
- package/dist/src/server.js +10 -93
- package/dist/src/server.js.map +1 -1
- package/dist/src/utils/safe-path.d.ts +66 -0
- package/dist/src/utils/safe-path.js +203 -0
- package/dist/src/utils/safe-path.js.map +1 -0
- package/package.json +2 -5
- package/project.faf +3 -3
- package/scripts/check-stylesheet-drift.mjs +1 -1
|
@@ -40,6 +40,7 @@ exports.handleFafRead = handleFafRead;
|
|
|
40
40
|
exports.handleFafWrite = handleFafWrite;
|
|
41
41
|
const fs = __importStar(require("fs/promises"));
|
|
42
42
|
const path = __importStar(require("path"));
|
|
43
|
+
const safe_path_1 = require("../utils/safe-path");
|
|
43
44
|
/**
|
|
44
45
|
* Security validator for file paths
|
|
45
46
|
*/
|
|
@@ -124,17 +125,21 @@ exports.fafWriteTool = {
|
|
|
124
125
|
async function handleFafRead(args) {
|
|
125
126
|
const startTime = Date.now();
|
|
126
127
|
try {
|
|
127
|
-
const { path:
|
|
128
|
-
//
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
128
|
+
const { path: rawPath } = args;
|
|
129
|
+
// Confine to the project root(s) — any file type, but no escape to
|
|
130
|
+
// /etc, ~/.ssh, or via ../ traversal (CWE-22). Returns symlink-canonical path.
|
|
131
|
+
let filePath;
|
|
132
|
+
try {
|
|
133
|
+
filePath = (0, safe_path_1.confineFileOp)(rawPath);
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
if (err instanceof safe_path_1.PathConfinementError) {
|
|
137
|
+
return {
|
|
138
|
+
content: [{ type: 'text', text: `❌ Security error: ${err.message}` }],
|
|
139
|
+
isError: true,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
throw err;
|
|
138
143
|
}
|
|
139
144
|
// Check file size
|
|
140
145
|
const sizeValidation = await PathValidator.checkFileSize(filePath);
|
|
@@ -183,17 +188,21 @@ async function handleFafRead(args) {
|
|
|
183
188
|
async function handleFafWrite(args) {
|
|
184
189
|
const startTime = Date.now();
|
|
185
190
|
try {
|
|
186
|
-
const { path:
|
|
187
|
-
//
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
191
|
+
const { path: rawPath, content } = args;
|
|
192
|
+
// Confine to the project root(s) before any write — closes arbitrary file
|
|
193
|
+
// write outside the project (e.g. overwriting ~/.bashrc).
|
|
194
|
+
let filePath;
|
|
195
|
+
try {
|
|
196
|
+
filePath = (0, safe_path_1.confineFileOp)(rawPath);
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
if (err instanceof safe_path_1.PathConfinementError) {
|
|
200
|
+
return {
|
|
201
|
+
content: [{ type: 'text', text: `❌ Security error: ${err.message}` }],
|
|
202
|
+
isError: true,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
throw err;
|
|
197
206
|
}
|
|
198
207
|
// Check content size
|
|
199
208
|
const contentSize = Buffer.byteLength(content, 'utf8');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileHandler.js","sourceRoot":"","sources":["../../../src/handlers/fileHandler.ts"],"names":[],"mappings":";AAAA,sCAAsC;AACtC,4DAA4D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"fileHandler.js","sourceRoot":"","sources":["../../../src/handlers/fileHandler.ts"],"names":[],"mappings":";AAAA,sCAAsC;AACtC,4DAA4D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8F5D,sCAkEC;AAKD,wCAqEC;AAxOD,gDAAkC;AAClC,2CAA6B;AAE7B,kDAAyE;AAEzE;;GAEG;AACH,MAAa,aAAa;IAChB,MAAM,CAAU,eAAe,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;IAC5E,MAAM,CAAU,aAAa,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO;IAEjE,MAAM,CAAC,QAAQ,CAAC,QAAgB;QAC9B,6BAA6B;QAC7B,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAExC,2BAA2B;QAC3B,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC;QAC5D,CAAC;QAED,wBAAwB;QACxB,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YAC7C,IAAI,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBACnC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,SAAS,eAAe,EAAE,CAAC;YACxE,CAAC;QACH,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACzB,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,QAAgB;QACzC,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtC,IAAI,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;gBACpC,OAAO;oBACL,KAAK,EAAE,KAAK;oBACZ,KAAK,EAAE,mBAAmB,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB;iBAChF,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACzB,CAAC;QAAC,OAAO,MAAe,EAAE,CAAC;YACzB,gDAAgD;YAChD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;;AAtCH,sCAuCC;AAED;;GAEG;AACU,QAAA,WAAW,GAAS;IAC/B,IAAI,EAAE,UAAU;IAChB,WAAW,EAAE,oDAAoD;IACjE,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,wCAAwC;aACtD;SACF;QACD,QAAQ,EAAE,CAAC,MAAM,CAAC;KACnB;CACF,CAAC;AAEF;;GAEG;AACU,QAAA,YAAY,GAAS;IAChC,IAAI,EAAE,WAAW;IACjB,WAAW,EAAE,mDAAmD;IAChE,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,yCAAyC;aACvD;YACD,OAAO,EAAE;gBACP,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,8BAA8B;aAC5C;SACF;QACD,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;KAC9B;CACF,CAAC;AAEF;;GAEG;AACI,KAAK,UAAU,aAAa,CAAC,IAAS;IAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,IAAI,CAAC;QACH,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;QAE/B,mEAAmE;QACnE,+EAA+E;QAC/E,IAAI,QAAgB,CAAC;QACrB,IAAI,CAAC;YACH,QAAQ,GAAG,IAAA,yBAAa,EAAC,OAAO,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,gCAAoB,EAAE,CAAC;gBACxC,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,qBAAqB,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;oBACrE,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,kBAAkB;QAClB,MAAM,cAAc,GAAG,MAAM,aAAa,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACnE,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;YAC1B,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,KAAK,cAAc,CAAC,KAAK,EAAE;qBAClC,CAAC;gBACF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,yBAAyB;QACzB,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;YACjC,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;YAC7B,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAC/B,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC,EAAE,KAAK,CAAC,CACjE;SACF,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACxC,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEtC,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,OAAO;iBACd,CAAC;YACF,QAAQ,EAAE;gBACR,WAAW,EAAE,QAAQ;gBACrB,SAAS,EAAE,KAAK,CAAC,IAAI;gBACrB,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;gBACjC,OAAO,EAAE,UAAU,KAAK,CAAC,IAAI,aAAa,QAAQ,IAAI;aACvD;SACF,CAAC;IAEJ,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,0BAA0B,KAAK,CAAC,OAAO,EAAE;iBAChD,CAAC;YACF,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,cAAc,CAAC,IAAS;IAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,IAAI,CAAC;QACH,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;QAExC,0EAA0E;QAC1E,0DAA0D;QAC1D,IAAI,QAAgB,CAAC;QACrB,IAAI,CAAC;YACH,QAAQ,GAAG,IAAA,yBAAa,EAAC,OAAO,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,gCAAoB,EAAE,CAAC;gBACxC,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,qBAAqB,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;oBACrE,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,qBAAqB;QACrB,MAAM,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACvD,IAAI,WAAW,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;YACnC,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,wBAAwB,CAAC,WAAW,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB;qBACrF,CAAC;gBACF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,6BAA6B;QAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEzC,0BAA0B;QAC1B,MAAM,OAAO,CAAC,IAAI,CAAC;YACjB,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC;YACvC,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAC/B,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC,EAAE,KAAK,CAAC,CAClE;SACF,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAExC,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,wBAAwB,WAAW,aAAa,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;iBAC/E,CAAC;YACF,QAAQ,EAAE;gBACR,WAAW,EAAE,QAAQ;gBACrB,aAAa,EAAE,WAAW;gBAC1B,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;gBACjC,OAAO,EAAE,wBAAwB,QAAQ,IAAI;aAC9C;SACF,CAAC;IAEJ,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,2BAA2B,KAAK,CAAC,OAAO,EAAE;iBACjD,CAAC;YACF,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC;AAED,kBAAkB;AACL,QAAA,YAAY,GAAG;IAC1B,QAAQ,EAAE,aAAa;IACvB,SAAS,EAAE,cAAc;CAC1B,CAAC"}
|
|
@@ -40,6 +40,7 @@ const os = __importStar(require("os"));
|
|
|
40
40
|
const pathModule = __importStar(require("path"));
|
|
41
41
|
const fuzzy_detector_1 = require("../utils/fuzzy-detector");
|
|
42
42
|
const faf_file_finder_js_1 = require("../utils/faf-file-finder.js");
|
|
43
|
+
const safe_path_1 = require("../utils/safe-path");
|
|
43
44
|
const version_1 = require("../version");
|
|
44
45
|
const path_resolver_1 = require("../utils/path-resolver");
|
|
45
46
|
// v2.1.1: single-source scoring — same path the championship handler uses.
|
|
@@ -66,12 +67,10 @@ class FafToolHandler {
|
|
|
66
67
|
*/
|
|
67
68
|
getProjectPath(explicitPath) {
|
|
68
69
|
if (explicitPath) {
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// Resolve to absolute path
|
|
74
|
-
const resolvedPath = pathModule.resolve(expandedPath);
|
|
70
|
+
// Confine the caller-supplied path. A passed *file* must be a .faf/.fafm
|
|
71
|
+
// context file; absolute/`..` escapes to secrets are refused. Throws
|
|
72
|
+
// PathConfinementError, caught centrally in callTool() (CWE-22/73/200).
|
|
73
|
+
const resolvedPath = (0, safe_path_1.confinePath)(explicitPath);
|
|
75
74
|
// If it's a file path, get the directory
|
|
76
75
|
const projectDir = fs.existsSync(resolvedPath) && fs.statSync(resolvedPath).isFile()
|
|
77
76
|
? pathModule.dirname(resolvedPath)
|
|
@@ -281,7 +280,7 @@ class FafToolHandler {
|
|
|
281
280
|
},
|
|
282
281
|
{
|
|
283
282
|
name: 'faf_read',
|
|
284
|
-
description: 'Read
|
|
283
|
+
description: 'Read a file within the project root (cwd / FAF_ALLOWED_ROOTS). Paths that escape the project are refused.',
|
|
285
284
|
annotations: {
|
|
286
285
|
title: 'Read .faf File',
|
|
287
286
|
readOnlyHint: true,
|
|
@@ -301,7 +300,7 @@ class FafToolHandler {
|
|
|
301
300
|
},
|
|
302
301
|
{
|
|
303
302
|
name: 'faf_write',
|
|
304
|
-
description: 'Write
|
|
303
|
+
description: 'Write a file within the project root (cwd / FAF_ALLOWED_ROOTS). Paths that escape the project are refused.',
|
|
305
304
|
annotations: {
|
|
306
305
|
title: 'Write .faf File',
|
|
307
306
|
readOnlyHint: false,
|
|
@@ -358,20 +357,9 @@ class FafToolHandler {
|
|
|
358
357
|
additionalProperties: false
|
|
359
358
|
}
|
|
360
359
|
},
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
annotations: {
|
|
365
|
-
title: 'Chat about FAF',
|
|
366
|
-
readOnlyHint: true,
|
|
367
|
-
openWorldHint: false
|
|
368
|
-
},
|
|
369
|
-
inputSchema: {
|
|
370
|
-
type: 'object',
|
|
371
|
-
properties: {},
|
|
372
|
-
additionalProperties: false
|
|
373
|
-
}
|
|
374
|
-
},
|
|
360
|
+
// faf_chat — DEPRECATED, un-advertised. The host IS the chat — a chat-shim
|
|
361
|
+
// tool is redundant. Dispatch keeps a deprecation stub (below). Fleet sweep —
|
|
362
|
+
// mirrors grok-faf-mcp + claude-faf-mcp's retire.
|
|
375
363
|
{
|
|
376
364
|
name: 'faf_friday',
|
|
377
365
|
description: '🎉 Friday Features - Chrome Extension detection, fuzzy matching & more! 🧡⚡️',
|
|
@@ -705,81 +693,91 @@ class FafToolHandler {
|
|
|
705
693
|
if (!name || typeof name !== 'string') {
|
|
706
694
|
throw new Error('Tool name must be a non-empty string');
|
|
707
695
|
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
696
|
+
try {
|
|
697
|
+
switch (name) {
|
|
698
|
+
case 'faf_status':
|
|
699
|
+
return await this.handleFafStatus(args);
|
|
700
|
+
case 'faf_score':
|
|
701
|
+
return await this.handleFafScore(args);
|
|
702
|
+
case 'faf_init':
|
|
703
|
+
return await this.handleFafInit(args);
|
|
704
|
+
case 'faf_trust':
|
|
705
|
+
return await this.handleFafTrust(args);
|
|
706
|
+
case 'faf_sync':
|
|
707
|
+
return await this.handleFafSync(args);
|
|
708
|
+
case 'faf_enhance':
|
|
709
|
+
return await this.handleFafEnhance(args);
|
|
710
|
+
case 'faf_bi_sync':
|
|
711
|
+
return await this.handleFafBiSync(args);
|
|
712
|
+
case 'faf_clear':
|
|
713
|
+
return await this.handleFafClear(args);
|
|
714
|
+
case 'faf_debug':
|
|
715
|
+
return await this.handleFafDebug(args);
|
|
716
|
+
case 'faf_about':
|
|
717
|
+
return await this.handleFafAbout(args);
|
|
718
|
+
case 'faf_what':
|
|
719
|
+
return await this.handleFafWhat(args);
|
|
720
|
+
case 'faf_read': {
|
|
721
|
+
// Handle faf_read specially to set context when reading project.faf files
|
|
722
|
+
const readResult = await fileHandler_1.fileHandlers.faf_read(args);
|
|
723
|
+
// If reading a project.faf file, set the session context
|
|
724
|
+
if (args?.path && (args.path.includes('project.faf') || args.path.endsWith('.faf'))) {
|
|
725
|
+
this.getProjectPath(args.path);
|
|
726
|
+
}
|
|
727
|
+
return readResult;
|
|
737
728
|
}
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
729
|
+
case 'faf_chat':
|
|
730
|
+
return await this.handleFafChat(args);
|
|
731
|
+
case 'faf_friday':
|
|
732
|
+
return await this.handleFafFriday(args);
|
|
733
|
+
case 'faf_write':
|
|
734
|
+
return await fileHandler_1.fileHandlers.faf_write(args);
|
|
735
|
+
case 'faf_list':
|
|
736
|
+
return await this.handleFafList(args);
|
|
737
|
+
case 'faf_guide':
|
|
738
|
+
return await this.handleFafGuide(args);
|
|
739
|
+
case 'faf_readme':
|
|
740
|
+
return await this.handleFafReadme(args);
|
|
741
|
+
case 'faf_human_add':
|
|
742
|
+
return await this.handleFafHumanAdd(args);
|
|
743
|
+
case 'faf_check':
|
|
744
|
+
return await this.handleFafCheck(args);
|
|
745
|
+
case 'faf_context':
|
|
746
|
+
return await this.handleFafContext(args);
|
|
747
|
+
case 'faf_go':
|
|
748
|
+
return await this.handleFafGo(args);
|
|
749
|
+
case 'faf_auto':
|
|
750
|
+
return await this.handleFafAuto(args);
|
|
751
|
+
case 'faf_dna':
|
|
752
|
+
return await this.handleFafDna(args);
|
|
753
|
+
case 'faf_formats':
|
|
754
|
+
return await this.handleFafFormats(args);
|
|
755
|
+
case 'faf_quick':
|
|
756
|
+
return await this.handleFafQuick(args);
|
|
757
|
+
case 'faf_doctor':
|
|
758
|
+
return await this.handleFafDoctor(args);
|
|
759
|
+
// v4.5.0 Interop tools
|
|
760
|
+
case 'faf_agents':
|
|
761
|
+
return await this.handleFafAgents(args);
|
|
762
|
+
case 'faf_cursor':
|
|
763
|
+
return await this.handleFafCursor(args);
|
|
764
|
+
case 'faf_gemini':
|
|
765
|
+
return await this.handleFafGemini(args);
|
|
766
|
+
case 'faf_conductor':
|
|
767
|
+
return await this.handleFafConductor(args);
|
|
768
|
+
case 'faf_git':
|
|
769
|
+
return await this.handleFafGit(args);
|
|
770
|
+
default:
|
|
771
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
catch (err) {
|
|
775
|
+
// Central catch for path-confinement violations from getProjectPath()
|
|
776
|
+
// (CWE-22/73/200). Anything else propagates unchanged.
|
|
777
|
+
if (err instanceof safe_path_1.PathConfinementError) {
|
|
778
|
+
return { content: [{ type: 'text', text: `PATH DENIED\n\n${err.message}` }], isError: true };
|
|
779
|
+
}
|
|
780
|
+
throw err;
|
|
783
781
|
}
|
|
784
782
|
}
|
|
785
783
|
async handleFafStatus(args) {
|
|
@@ -1307,37 +1305,17 @@ ${debugInfo.permissions.fafError ? ` FAF Error: ${debugInfo.permissions.fafErr
|
|
|
1307
1305
|
}
|
|
1308
1306
|
}
|
|
1309
1307
|
async handleFafChat(_args) {
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
|
-
// Format the response text
|
|
1322
|
-
const responseText = typeof result.data === 'string'
|
|
1323
|
-
? result.data
|
|
1324
|
-
: result.data?.output || JSON.stringify(result.data, null, 2);
|
|
1325
|
-
return {
|
|
1326
|
-
content: [{
|
|
1327
|
-
type: 'text',
|
|
1328
|
-
text: responseText
|
|
1329
|
-
}]
|
|
1330
|
-
};
|
|
1331
|
-
}
|
|
1332
|
-
catch (error) {
|
|
1333
|
-
return {
|
|
1334
|
-
content: [{
|
|
1335
|
-
type: 'text',
|
|
1336
|
-
text: `Error running faf chat: ${error instanceof Error ? error.message : String(error)}`
|
|
1337
|
-
}],
|
|
1338
|
-
isError: true
|
|
1339
|
-
};
|
|
1340
|
-
}
|
|
1308
|
+
// DEPRECATED: the host IS the chat — a chat-shim MCP tool is redundant.
|
|
1309
|
+
// Un-advertised in listTools; this stub stays so anyone still wired gets a
|
|
1310
|
+
// clear signal, not a crash. The old body shelled `faf chat` via the engine
|
|
1311
|
+
// subprocess (a command faf-cli no longer ships) — removing it ends that dead shell.
|
|
1312
|
+
return {
|
|
1313
|
+
content: [{
|
|
1314
|
+
type: 'text',
|
|
1315
|
+
text: 'faf_chat is retired — the host is your chat, just talk here. ' +
|
|
1316
|
+
'For FAF: faf_init / faf_score / faf_sync, or "ask questions" to build context.',
|
|
1317
|
+
}],
|
|
1318
|
+
};
|
|
1341
1319
|
}
|
|
1342
1320
|
async handleFafFriday(args) {
|
|
1343
1321
|
const { test } = args || {};
|