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.
Files changed (35) hide show
  1. package/CHANGELOG.md +30 -1
  2. package/CLAUDE.md +3 -3
  3. package/README.md +8 -7
  4. package/dist/src/cli.js +2 -15
  5. package/dist/src/cli.js.map +1 -1
  6. package/dist/src/faf-core/commands/bi-sync.js +3 -2
  7. package/dist/src/faf-core/commands/bi-sync.js.map +1 -1
  8. package/dist/src/faf-core/compiler/faf-compiler.js +65 -6
  9. package/dist/src/faf-core/compiler/faf-compiler.js.map +1 -1
  10. package/dist/src/faf-core/inject.d.ts +19 -0
  11. package/dist/src/faf-core/inject.js +57 -0
  12. package/dist/src/faf-core/inject.js.map +1 -0
  13. package/dist/src/faf-core/parsers/agents-parser.js +3 -2
  14. package/dist/src/faf-core/parsers/agents-parser.js.map +1 -1
  15. package/dist/src/faf-core/parsers/cursorrules-parser.js +6 -2
  16. package/dist/src/faf-core/parsers/cursorrules-parser.js.map +1 -1
  17. package/dist/src/faf-core/parsers/gemini-parser.js +3 -2
  18. package/dist/src/faf-core/parsers/gemini-parser.js.map +1 -1
  19. package/dist/src/handlers/championship-tools.js +11 -11
  20. package/dist/src/handlers/championship-tools.js.map +1 -1
  21. package/dist/src/handlers/cloud-handler.js +1 -1
  22. package/dist/src/handlers/cloud-handler.js.map +1 -1
  23. package/dist/src/handlers/fileHandler.js +31 -22
  24. package/dist/src/handlers/fileHandler.js.map +1 -1
  25. package/dist/src/handlers/tools.js +105 -127
  26. package/dist/src/handlers/tools.js.map +1 -1
  27. package/dist/src/server.d.ts +2 -4
  28. package/dist/src/server.js +10 -93
  29. package/dist/src/server.js.map +1 -1
  30. package/dist/src/utils/safe-path.d.ts +66 -0
  31. package/dist/src/utils/safe-path.js +203 -0
  32. package/dist/src/utils/safe-path.js.map +1 -0
  33. package/package.json +2 -5
  34. package/project.faf +3 -3
  35. 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: filePath } = args;
128
- // Validate path
129
- const pathValidation = PathValidator.validate(filePath);
130
- if (!pathValidation.valid) {
131
- return {
132
- content: [{
133
- type: 'text',
134
- text: `❌ Security error: ${pathValidation.error}`
135
- }],
136
- isError: true
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: filePath, content } = args;
187
- // Validate path
188
- const pathValidation = PathValidator.validate(filePath);
189
- if (!pathValidation.valid) {
190
- return {
191
- content: [{
192
- type: 'text',
193
- text: `❌ Security error: ${pathValidation.error}`
194
- }],
195
- isError: true
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":"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"}
1
+ {"version":3,"file":"fileHandler.js","sourceRoot":"","sources":["../../../src/handlers/fileHandler.ts"],"names":[],"mappings":"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"}
@@ -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
- // Expand tilde
70
- const expandedPath = explicitPath.startsWith('~')
71
- ? pathModule.join(os.homedir(), explicitPath.slice(1))
72
- : explicitPath;
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 content from any file on the local filesystem',
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 content to any file on the local filesystem',
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
- name: 'faf_chat',
363
- description: '🗣️ Natural language project.faf generation - Ask 6W questions (Who/What/Why/Where/When/How) to build complete human context 🧡⚡️',
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
- switch (name) {
709
- case 'faf_status':
710
- return await this.handleFafStatus(args);
711
- case 'faf_score':
712
- return await this.handleFafScore(args);
713
- case 'faf_init':
714
- return await this.handleFafInit(args);
715
- case 'faf_trust':
716
- return await this.handleFafTrust(args);
717
- case 'faf_sync':
718
- return await this.handleFafSync(args);
719
- case 'faf_enhance':
720
- return await this.handleFafEnhance(args);
721
- case 'faf_bi_sync':
722
- return await this.handleFafBiSync(args);
723
- case 'faf_clear':
724
- return await this.handleFafClear(args);
725
- case 'faf_debug':
726
- return await this.handleFafDebug(args);
727
- case 'faf_about':
728
- return await this.handleFafAbout(args);
729
- case 'faf_what':
730
- return await this.handleFafWhat(args);
731
- case 'faf_read': {
732
- // Handle faf_read specially to set context when reading project.faf files
733
- const readResult = await fileHandler_1.fileHandlers.faf_read(args);
734
- // If reading a project.faf file, set the session context
735
- if (args?.path && (args.path.includes('project.faf') || args.path.endsWith('.faf'))) {
736
- this.getProjectPath(args.path);
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
- return readResult;
739
- }
740
- case 'faf_chat':
741
- return await this.handleFafChat(args);
742
- case 'faf_friday':
743
- return await this.handleFafFriday(args);
744
- case 'faf_write':
745
- return await fileHandler_1.fileHandlers.faf_write(args);
746
- case 'faf_list':
747
- return await this.handleFafList(args);
748
- case 'faf_guide':
749
- return await this.handleFafGuide(args);
750
- case 'faf_readme':
751
- return await this.handleFafReadme(args);
752
- case 'faf_human_add':
753
- return await this.handleFafHumanAdd(args);
754
- case 'faf_check':
755
- return await this.handleFafCheck(args);
756
- case 'faf_context':
757
- return await this.handleFafContext(args);
758
- case 'faf_go':
759
- return await this.handleFafGo(args);
760
- case 'faf_auto':
761
- return await this.handleFafAuto(args);
762
- case 'faf_dna':
763
- return await this.handleFafDna(args);
764
- case 'faf_formats':
765
- return await this.handleFafFormats(args);
766
- case 'faf_quick':
767
- return await this.handleFafQuick(args);
768
- case 'faf_doctor':
769
- return await this.handleFafDoctor(args);
770
- // v4.5.0 Interop tools
771
- case 'faf_agents':
772
- return await this.handleFafAgents(args);
773
- case 'faf_cursor':
774
- return await this.handleFafCursor(args);
775
- case 'faf_gemini':
776
- return await this.handleFafGemini(args);
777
- case 'faf_conductor':
778
- return await this.handleFafConductor(args);
779
- case 'faf_git':
780
- return await this.handleFafGit(args);
781
- default:
782
- throw new Error(`Unknown tool: ${name}`);
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
- try {
1311
- const result = await this.engineAdapter.callEngine('chat');
1312
- if (!result.success) {
1313
- return {
1314
- content: [{
1315
- type: 'text',
1316
- text: `Error running faf chat: ${result.error || 'Unknown error'}`
1317
- }],
1318
- isError: true
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 || {};