faf-mcp 2.3.0 → 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.
Files changed (178) hide show
  1. package/CHANGELOG.md +42 -3
  2. package/CLAUDE.md +7 -7
  3. package/README.md +73 -74
  4. package/dist/src/faf-core/commands/bi-sync.d.ts +1 -3
  5. package/dist/src/faf-core/commands/bi-sync.js +21 -64
  6. package/dist/src/faf-core/commands/bi-sync.js.map +1 -1
  7. package/dist/src/faf-core/commands/sync.js.map +1 -1
  8. package/dist/src/faf-core/engines/dependency-tsa.js.map +1 -1
  9. package/dist/src/faf-core/fix-once/colors.js +1 -1
  10. package/dist/src/faf-core/fix-once/colors.js.map +1 -1
  11. package/dist/src/faf-core/parsers/agents-parser.d.ts +15 -0
  12. package/dist/src/faf-core/parsers/agents-parser.js +29 -123
  13. package/dist/src/faf-core/parsers/agents-parser.js.map +1 -1
  14. package/dist/src/faf-core/parsers/conductor-parser.js +1 -1
  15. package/dist/src/faf-core/parsers/conductor-parser.js.map +1 -1
  16. package/dist/src/faf-core/parsers/cursorrules-parser.d.ts +15 -0
  17. package/dist/src/faf-core/parsers/cursorrules-parser.js +54 -111
  18. package/dist/src/faf-core/parsers/cursorrules-parser.js.map +1 -1
  19. package/dist/src/faf-core/parsers/faf-git-generator.js +0 -1
  20. package/dist/src/faf-core/parsers/faf-git-generator.js.map +1 -1
  21. package/dist/src/faf-core/parsers/gemini-parser.d.ts +10 -0
  22. package/dist/src/faf-core/parsers/gemini-parser.js +19 -77
  23. package/dist/src/faf-core/parsers/gemini-parser.js.map +1 -1
  24. package/dist/src/handlers/engine-adapter.d.ts +13 -12
  25. package/dist/src/handlers/engine-adapter.js +124 -688
  26. package/dist/src/handlers/engine-adapter.js.map +1 -1
  27. package/dist/src/handlers/resources.d.ts +19 -1
  28. package/dist/src/handlers/resources.js +108 -23
  29. package/dist/src/handlers/resources.js.map +1 -1
  30. package/dist/src/handlers/skills.d.ts +70 -0
  31. package/dist/src/handlers/skills.js +174 -0
  32. package/dist/src/handlers/skills.js.map +1 -0
  33. package/dist/src/handlers/tools.d.ts +41 -5
  34. package/dist/src/handlers/tools.js +213 -258
  35. package/dist/src/handlers/tools.js.map +1 -1
  36. package/dist/src/server.d.ts +4 -0
  37. package/dist/src/server.js +51 -6
  38. package/dist/src/server.js.map +1 -1
  39. package/dist/src/utils/faf-cli-bridge.d.ts +2 -0
  40. package/dist/src/utils/faf-cli-bridge.js +16 -0
  41. package/dist/src/utils/faf-cli-bridge.js.map +1 -1
  42. package/package.json +17 -14
  43. package/project.faf +23 -5
  44. package/scripts/check-engines.mjs +53 -0
  45. package/scripts/run-tests.sh +54 -0
  46. package/scripts/sync-version.js +33 -19
  47. package/skills/faf-ide/SKILL.md +40 -0
  48. package/dist/src/config/visibility.d.ts +0 -41
  49. package/dist/src/config/visibility.js +0 -158
  50. package/dist/src/config/visibility.js.map +0 -1
  51. package/dist/src/faf-core/commands/audit.d.ts +0 -21
  52. package/dist/src/faf-core/commands/audit.js +0 -83
  53. package/dist/src/faf-core/commands/audit.js.map +0 -1
  54. package/dist/src/faf-core/commands/auto.d.ts +0 -25
  55. package/dist/src/faf-core/commands/auto.js +0 -74
  56. package/dist/src/faf-core/commands/auto.js.map +0 -1
  57. package/dist/src/faf-core/commands/doctor.d.ts +0 -17
  58. package/dist/src/faf-core/commands/doctor.js +0 -198
  59. package/dist/src/faf-core/commands/doctor.js.map +0 -1
  60. package/dist/src/faf-core/commands/enhance.d.ts +0 -46
  61. package/dist/src/faf-core/commands/enhance.js +0 -360
  62. package/dist/src/faf-core/commands/enhance.js.map +0 -1
  63. package/dist/src/faf-core/commands/formats.d.ts +0 -22
  64. package/dist/src/faf-core/commands/formats.js +0 -117
  65. package/dist/src/faf-core/commands/formats.js.map +0 -1
  66. package/dist/src/faf-core/commands/human.d.ts +0 -27
  67. package/dist/src/faf-core/commands/human.js +0 -183
  68. package/dist/src/faf-core/commands/human.js.map +0 -1
  69. package/dist/src/faf-core/commands/init.d.ts +0 -26
  70. package/dist/src/faf-core/commands/init.js +0 -114
  71. package/dist/src/faf-core/commands/init.js.map +0 -1
  72. package/dist/src/faf-core/commands/innit.d.ts +0 -7
  73. package/dist/src/faf-core/commands/innit.js +0 -13
  74. package/dist/src/faf-core/commands/innit.js.map +0 -1
  75. package/dist/src/faf-core/commands/migrate.d.ts +0 -15
  76. package/dist/src/faf-core/commands/migrate.js +0 -86
  77. package/dist/src/faf-core/commands/migrate.js.map +0 -1
  78. package/dist/src/faf-core/commands/quick.d.ts +0 -16
  79. package/dist/src/faf-core/commands/quick.js +0 -184
  80. package/dist/src/faf-core/commands/quick.js.map +0 -1
  81. package/dist/src/faf-core/commands/readme.d.ts +0 -47
  82. package/dist/src/faf-core/commands/readme.js +0 -361
  83. package/dist/src/faf-core/commands/readme.js.map +0 -1
  84. package/dist/src/faf-core/commands/score.d.ts +0 -47
  85. package/dist/src/faf-core/commands/score.js +0 -49
  86. package/dist/src/faf-core/commands/score.js.map +0 -1
  87. package/dist/src/faf-core/commands/update.d.ts +0 -12
  88. package/dist/src/faf-core/commands/update.js +0 -46
  89. package/dist/src/faf-core/commands/update.js.map +0 -1
  90. package/dist/src/faf-core/commands/validate.d.ts +0 -21
  91. package/dist/src/faf-core/commands/validate.js +0 -81
  92. package/dist/src/faf-core/commands/validate.js.map +0 -1
  93. package/dist/src/faf-core/compiler/faf-compiler.d.ts +0 -138
  94. package/dist/src/faf-core/compiler/faf-compiler.js +0 -1362
  95. package/dist/src/faf-core/compiler/faf-compiler.js.map +0 -1
  96. package/dist/src/faf-core/engines/fab-formats-processor.d.ts +0 -166
  97. package/dist/src/faf-core/engines/fab-formats-processor.js +0 -1274
  98. package/dist/src/faf-core/engines/fab-formats-processor.js.map +0 -1
  99. package/dist/src/faf-core/engines/faf-dna.d.ts +0 -159
  100. package/dist/src/faf-core/engines/faf-dna.js +0 -555
  101. package/dist/src/faf-core/engines/faf-dna.js.map +0 -1
  102. package/dist/src/faf-core/engines/relentless-context-extractor.d.ts +0 -100
  103. package/dist/src/faf-core/engines/relentless-context-extractor.js +0 -625
  104. package/dist/src/faf-core/engines/relentless-context-extractor.js.map +0 -1
  105. package/dist/src/faf-core/fix-once/types.d.ts +0 -257
  106. package/dist/src/faf-core/fix-once/types.js +0 -26
  107. package/dist/src/faf-core/fix-once/types.js.map +0 -1
  108. package/dist/src/faf-core/generators/faf-generator-championship.d.ts +0 -16
  109. package/dist/src/faf-core/generators/faf-generator-championship.js +0 -463
  110. package/dist/src/faf-core/generators/faf-generator-championship.js.map +0 -1
  111. package/dist/src/faf-core/inject.d.ts +0 -19
  112. package/dist/src/faf-core/inject.js +0 -57
  113. package/dist/src/faf-core/inject.js.map +0 -1
  114. package/dist/src/faf-core/parsers/index.d.ts +0 -12
  115. package/dist/src/faf-core/parsers/index.js +0 -29
  116. package/dist/src/faf-core/parsers/index.js.map +0 -1
  117. package/dist/src/faf-core/utils/balance-visualizer.d.ts +0 -37
  118. package/dist/src/faf-core/utils/balance-visualizer.js +0 -197
  119. package/dist/src/faf-core/utils/balance-visualizer.js.map +0 -1
  120. package/dist/src/faf-core/utils/championship-style.d.ts +0 -109
  121. package/dist/src/faf-core/utils/championship-style.js +0 -219
  122. package/dist/src/faf-core/utils/championship-style.js.map +0 -1
  123. package/dist/src/faf-core/utils/chrome-extension-detector.d.ts +0 -73
  124. package/dist/src/faf-core/utils/chrome-extension-detector.js +0 -268
  125. package/dist/src/faf-core/utils/chrome-extension-detector.js.map +0 -1
  126. package/dist/src/faf-core/utils/platform-detector.d.ts +0 -30
  127. package/dist/src/faf-core/utils/platform-detector.js +0 -218
  128. package/dist/src/faf-core/utils/platform-detector.js.map +0 -1
  129. package/dist/src/faf-core/utils/technical-credit.d.ts +0 -35
  130. package/dist/src/faf-core/utils/technical-credit.js +0 -286
  131. package/dist/src/faf-core/utils/technical-credit.js.map +0 -1
  132. package/dist/src/faf-core/utils/yaml-generator.d.ts +0 -41
  133. package/dist/src/faf-core/utils/yaml-generator.js +0 -360
  134. package/dist/src/faf-core/utils/yaml-generator.js.map +0 -1
  135. package/dist/src/handlers/behavioral-instruction.d.ts +0 -16
  136. package/dist/src/handlers/behavioral-instruction.js +0 -43
  137. package/dist/src/handlers/behavioral-instruction.js.map +0 -1
  138. package/dist/src/handlers/championship-tools.d.ts +0 -116
  139. package/dist/src/handlers/championship-tools.js +0 -2320
  140. package/dist/src/handlers/championship-tools.js.map +0 -1
  141. package/dist/src/handlers/cloud-handler.d.ts +0 -59
  142. package/dist/src/handlers/cloud-handler.js +0 -348
  143. package/dist/src/handlers/cloud-handler.js.map +0 -1
  144. package/dist/src/handlers/tool-registry.d.ts +0 -23
  145. package/dist/src/handlers/tool-registry.js +0 -68
  146. package/dist/src/handlers/tool-registry.js.map +0 -1
  147. package/dist/src/handlers/tool-types.d.ts +0 -167
  148. package/dist/src/handlers/tool-types.js +0 -7
  149. package/dist/src/handlers/tool-types.js.map +0 -1
  150. package/dist/src/test-all-functions.d.ts +0 -15
  151. package/dist/src/test-all-functions.js +0 -163
  152. package/dist/src/test-all-functions.js.map +0 -1
  153. package/dist/src/types/mcp-tools.d.ts +0 -53
  154. package/dist/src/types/mcp-tools.js +0 -77
  155. package/dist/src/types/mcp-tools.js.map +0 -1
  156. package/dist/src/types/tool-visibility.d.ts +0 -36
  157. package/dist/src/types/tool-visibility.js +0 -551
  158. package/dist/src/types/tool-visibility.js.map +0 -1
  159. package/dist/src/utils/auto-path-detection.d.ts +0 -26
  160. package/dist/src/utils/auto-path-detection.js +0 -198
  161. package/dist/src/utils/auto-path-detection.js.map +0 -1
  162. package/dist/src/utils/championship-format.d.ts +0 -30
  163. package/dist/src/utils/championship-format.js +0 -81
  164. package/dist/src/utils/championship-format.js.map +0 -1
  165. package/dist/src/utils/cli-detector.d.ts +0 -17
  166. package/dist/src/utils/cli-detector.js +0 -247
  167. package/dist/src/utils/cli-detector.js.map +0 -1
  168. package/dist/src/utils/display-protocol.d.ts +0 -57
  169. package/dist/src/utils/display-protocol.js +0 -131
  170. package/dist/src/utils/display-protocol.js.map +0 -1
  171. package/dist/src/utils/username-detector.d.ts +0 -27
  172. package/dist/src/utils/username-detector.js +0 -90
  173. package/dist/src/utils/username-detector.js.map +0 -1
  174. package/dist/src/utils/visual-style.d.ts +0 -62
  175. package/dist/src/utils/visual-style.js +0 -166
  176. package/dist/src/utils/visual-style.js.map +0 -1
  177. package/scripts/postinstall.js +0 -50
  178. package/skill/SKILL.md +0 -385
@@ -34,86 +34,43 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.FafEngineAdapter = void 0;
37
- const child_process_1 = require("child_process");
38
- const util_1 = require("util");
37
+ /**
38
+ * FafEngineAdapter — routes the interop tools to their bundled, in-process
39
+ * commands.
40
+ *
41
+ * Every faf-mcp tool runs in-process: scoring, init, auto, trust, status and
42
+ * the resources go through src/utils/faf-cli-bridge.ts (the faf-cli this
43
+ * package bundles); the seven interop commands below run the vendored
44
+ * faf-core modules. Nothing shells out.
45
+ *
46
+ * History (3.0 P2): this file used to carry 22 command branches, a
47
+ * `which faf` detector that ran at every server start, and an exec fallback
48
+ * that spawned whatever binary the detector found — on machines with an
49
+ * unrelated `faf` on PATH that was a different program entirely. Only seven
50
+ * branches were ever reached by a registered tool; the rest, the detector
51
+ * and the fallback are gone (archive tag: archive/pre-p2-dead-code).
52
+ */
39
53
  const path = __importStar(require("path"));
40
54
  const fs = __importStar(require("fs"));
41
- const type_guards_js_1 = require("../utils/type-guards.js"); // ✅ FIXED: Removed unused isDefined
42
- const cli_detector_js_1 = require("../utils/cli-detector.js");
43
- const score_js_1 = require("../faf-core/commands/score.js");
44
- const init_js_1 = require("../faf-core/commands/init.js");
45
- const auto_js_1 = require("../faf-core/commands/auto.js");
55
+ const type_guards_js_1 = require("../utils/type-guards.js");
46
56
  const sync_js_1 = require("../faf-core/commands/sync.js");
47
57
  const bi_sync_js_1 = require("../faf-core/commands/bi-sync.js");
48
- const formats_js_1 = require("../faf-core/commands/formats.js");
49
- const doctor_js_1 = require("../faf-core/commands/doctor.js");
50
- const validate_js_1 = require("../faf-core/commands/validate.js");
51
- const audit_js_1 = require("../faf-core/commands/audit.js");
52
- const update_js_1 = require("../faf-core/commands/update.js");
53
- const migrate_js_1 = require("../faf-core/commands/migrate.js");
54
- const innit_js_1 = require("../faf-core/commands/innit.js");
55
- const quick_js_1 = require("../faf-core/commands/quick.js");
56
- const human_js_1 = require("../faf-core/commands/human.js");
57
- const readme_js_1 = require("../faf-core/commands/readme.js");
58
- // v4.5.0 Interop commands
59
58
  const agents_js_1 = require("../faf-core/commands/agents.js");
60
59
  const cursor_js_1 = require("../faf-core/commands/cursor.js");
61
60
  const gemini_js_1 = require("../faf-core/commands/gemini.js");
62
61
  const conductor_js_1 = require("../faf-core/commands/conductor.js");
63
62
  const git_context_js_1 = require("../faf-core/commands/git-context.js");
64
- const execAsync = (0, util_1.promisify)(child_process_1.exec);
65
- // Enhanced PATH for FAF CLI discovery
66
- const getEnhancedEnv = () => ({
67
- ...process.env,
68
- PATH: [
69
- '/usr/local/bin',
70
- '/opt/homebrew/bin',
71
- process.env.HOME ? `${process.env.HOME}/.npm/bin` : undefined,
72
- process.env.HOME ? `${process.env.HOME}/.npm-global/bin` : undefined,
73
- '/usr/bin',
74
- '/bin',
75
- process.env.PATH
76
- ].filter(Boolean).join(':')
77
- });
78
63
  class FafEngineAdapter {
79
64
  enginePath;
80
- detectedCliPath = null;
81
- cliVersion;
82
- timeout;
83
65
  workingDirectory;
84
- constructor(enginePath = 'faf', timeout = 30000) {
66
+ /**
67
+ * `enginePath` is kept for the config surface (server.ts passes it through;
68
+ * faf_debug reports it). `_timeout` was the exec fallback's — retained in
69
+ * the signature so callers do not break, unused now that nothing spawns.
70
+ */
71
+ constructor(enginePath = 'native', _timeout = 30000) {
85
72
  this.enginePath = enginePath;
86
- this.timeout = timeout;
87
73
  this.workingDirectory = this.findBestWorkingDirectory();
88
- // Auto-detect CLI on initialization
89
- this.detectCli();
90
- }
91
- detectCli() {
92
- const detection = (0, cli_detector_js_1.detectFafCli)();
93
- if (detection.found && detection.path) {
94
- this.detectedCliPath = detection.path;
95
- this.cliVersion = detection.version;
96
- // Validate version meets minimum requirement
97
- if (this.cliVersion && !(0, cli_detector_js_1.validateCliVersion)(this.cliVersion, '3.1.1')) {
98
- console.warn(`FAF CLI version ${this.cliVersion} is below minimum required version 3.1.1. Some features may not work correctly.`);
99
- }
100
- console.error(`✅ FAF CLI detected: ${this.detectedCliPath} (v${this.cliVersion || 'unknown'}) via ${detection.method}`);
101
- }
102
- else {
103
- console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
104
- console.error('⚠️ FAF CLI NOT DETECTED');
105
- console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
106
- console.error('');
107
- console.error('INSTALLATION ORDER REQUIRED:');
108
- console.error(' 1️⃣ npm install -g faf-cli (REQUIRED FIRST)');
109
- console.error(' 2️⃣ npm install -g faf-mcp (THEN THIS)');
110
- console.error('');
111
- console.error('Most MCP tools require faf-cli to be installed.');
112
- console.error('Only basic file operations will work without it.');
113
- console.error('');
114
- console.error('After installing faf-cli, restart your MCP host.');
115
- console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
116
- }
117
74
  }
118
75
  findBestWorkingDirectory() {
119
76
  // Priority 1: Environment variable for explicit control
@@ -126,7 +83,27 @@ class FafEngineAdapter {
126
83
  if (mcpWorkingDir && fs.existsSync(mcpWorkingDir)) {
127
84
  return mcpWorkingDir;
128
85
  }
129
- // Priority 3: FORCE ~/Projects as universal default
86
+ // Priority 3 (FIX 2026-06-30): the caller's ACTUAL working directory — the
87
+ // workspace an IDE / MCP host (Cursor, VS Code, Claude Desktop) launches the
88
+ // server in. This MUST win over the ~/Projects convention below. Previously
89
+ // ~/Projects was FORCED here, so every no-path tool call (faf_score, …)
90
+ // operated on ~/Projects instead of the project the user actually had open —
91
+ // the editor surface's whole value, silently broken (scored ~/Projects's
92
+ // stale .faf for everyone). Prefer a real FAF project (cwd contains
93
+ // project.faf — the path-check), else the cwd itself when it's a usable,
94
+ // non-root directory (so faf_init/score act on the open workspace even
95
+ // before a .faf exists).
96
+ const currentDir = process.cwd();
97
+ const usableCwd = currentDir !== '/' && currentDir !== '/root' && fs.existsSync(currentDir);
98
+ if (usableCwd && fs.existsSync(path.join(currentDir, 'project.faf'))) {
99
+ return currentDir;
100
+ }
101
+ if (usableCwd) {
102
+ return currentDir;
103
+ }
104
+ // Priority 4: ~/Projects convention — a soft landing ONLY when the host gave
105
+ // us no usable workspace (e.g. cwd is the filesystem root). Never overrides a
106
+ // real cwd above.
130
107
  const homeDir = process.env.HOME ?? process.env.USERPROFILE;
131
108
  if (homeDir) {
132
109
  // Try capitalized Projects first (macOS/Windows convention)
@@ -149,632 +126,99 @@ class FafEngineAdapter {
149
126
  return homeDir;
150
127
  }
151
128
  }
152
- // Priority 4: Current directory if not root
153
- const currentDir = process.cwd();
154
- if (currentDir !== '/' && currentDir !== '/root' && fs.existsSync(currentDir)) {
155
- return currentDir;
156
- }
157
129
  // Last resort: /tmp (should rarely happen)
158
130
  return '/tmp';
159
131
  }
132
+ /**
133
+ * Wrap a bundled command's outcome. A failed command's reason travels in
134
+ * `error` so handlers can print it — previously the bundled branches set
135
+ * only `success` and users saw "❌ undefined".
136
+ */
137
+ outcome(result, fallback, startTime) {
138
+ return {
139
+ success: result.success,
140
+ data: result,
141
+ error: result.success ? undefined : (result.message || result.error || fallback),
142
+ duration: Date.now() - startTime,
143
+ };
144
+ }
145
+ failure(error, fallback, startTime) {
146
+ return { success: false, error: (0, type_guards_js_1.isError)(error) ? error.message : fallback, duration: Date.now() - startTime };
147
+ }
160
148
  async callEngine(command, args = []) {
161
149
  const startTime = Date.now();
162
- // Input validation
163
150
  if (!command || typeof command !== 'string') {
164
- return {
165
- success: false,
166
- error: 'Command must be a non-empty string',
167
- duration: 0
168
- };
169
- }
170
- // ============================================================================
171
- // MK3 BUNDLED ENGINE - Direct function calls (no CLI dependency!)
172
- // ============================================================================
173
- // SCORE command - use bundled FafCompiler
174
- if (command === 'score') {
175
- try {
176
- const filePath = args[0] || this.workingDirectory;
177
- const result = await (0, score_js_1.scoreFafFile)(filePath, { json: true });
178
- const duration = Date.now() - startTime;
179
- return {
180
- success: true,
181
- data: result,
182
- duration
183
- };
184
- }
185
- catch (error) {
186
- const duration = Date.now() - startTime;
187
- const errorMessage = (0, type_guards_js_1.isError)(error) ? error.message : 'Score command failed';
188
- return {
189
- success: false,
190
- error: errorMessage,
191
- duration
192
- };
193
- }
194
- }
195
- // INIT command - use bundled init
196
- if (command === 'init') {
197
- try {
198
- // Filter out flags to get the actual path argument
199
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
200
- const projectPath = pathArgs[0] || this.workingDirectory;
201
- const force = args.includes('--force');
202
- const result = await (0, init_js_1.initFafFile)(projectPath, { force });
203
- const duration = Date.now() - startTime;
204
- return {
205
- success: result.success,
206
- data: result,
207
- duration
208
- };
209
- }
210
- catch (error) {
211
- const duration = Date.now() - startTime;
212
- const errorMessage = (0, type_guards_js_1.isError)(error) ? error.message : 'Init command failed';
213
- return {
214
- success: false,
215
- error: errorMessage,
216
- duration
217
- };
218
- }
219
- }
220
- // AUTO command - use bundled auto (init + score)
221
- if (command === 'auto') {
222
- try {
223
- // Filter out flags to get the actual path argument
224
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
225
- const directory = pathArgs[0] || this.workingDirectory;
226
- const force = args.includes('--force');
227
- const result = await (0, auto_js_1.autoCommand)(directory, { force });
228
- const duration = Date.now() - startTime;
229
- return {
230
- success: result.success,
231
- data: result,
232
- duration
233
- };
234
- }
235
- catch (error) {
236
- const duration = Date.now() - startTime;
237
- const errorMessage = (0, type_guards_js_1.isError)(error) ? error.message : 'Auto command failed';
238
- return {
239
- success: false,
240
- error: errorMessage,
241
- duration
242
- };
243
- }
244
- }
245
- // SYNC command - use bundled sync
246
- if (command === 'sync') {
247
- try {
248
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
249
- const projectPath = pathArgs[0] || this.workingDirectory;
250
- const auto = args.includes('--auto');
251
- const result = await (0, sync_js_1.syncFafFile)(projectPath, { auto, json: true });
252
- const duration = Date.now() - startTime;
253
- return {
254
- success: result.success,
255
- data: result,
256
- duration
257
- };
258
- }
259
- catch (error) {
260
- const duration = Date.now() - startTime;
261
- return {
262
- success: false,
263
- error: (0, type_guards_js_1.isError)(error) ? error.message : 'Sync command failed',
264
- duration
265
- };
266
- }
267
- }
268
- // BI-SYNC command - use bundled bi-sync (v4.5.0: supports agents/cursor/gemini/all flags)
269
- if (command === 'bi-sync' || command === 'bisync') {
270
- try {
271
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
272
- const projectPath = pathArgs[0] || this.workingDirectory;
273
- const result = await (0, bi_sync_js_1.syncBiDirectional)(projectPath, {
274
- json: true,
275
- agents: args.includes('--agents'),
276
- cursor: args.includes('--cursor'),
277
- gemini: args.includes('--gemini'),
278
- all: args.includes('--all'),
279
- });
280
- const duration = Date.now() - startTime;
281
- return {
282
- success: result.success,
283
- data: result,
284
- duration
285
- };
286
- }
287
- catch (error) {
288
- const duration = Date.now() - startTime;
289
- return {
290
- success: false,
291
- error: (0, type_guards_js_1.isError)(error) ? error.message : 'Bi-sync command failed',
292
- duration
293
- };
294
- }
295
- }
296
- // FORMATS command - use bundled formats
297
- if (command === 'formats') {
298
- try {
299
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
300
- const projectPath = pathArgs[0] || this.workingDirectory;
301
- const result = await (0, formats_js_1.formatsCommand)(projectPath, { json: true });
302
- const duration = Date.now() - startTime;
303
- return {
304
- success: result.success,
305
- data: result,
306
- duration
307
- };
308
- }
309
- catch (error) {
310
- const duration = Date.now() - startTime;
311
- return {
312
- success: false,
313
- error: (0, type_guards_js_1.isError)(error) ? error.message : 'Formats command failed',
314
- duration
315
- };
316
- }
317
- }
318
- // DOCTOR command - use bundled doctor
319
- if (command === 'doctor') {
320
- try {
321
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
322
- const projectPath = pathArgs[0] || this.workingDirectory;
323
- const result = await (0, doctor_js_1.doctorCommand)(projectPath);
324
- const duration = Date.now() - startTime;
325
- return {
326
- success: result.success,
327
- data: result,
328
- duration
329
- };
330
- }
331
- catch (error) {
332
- const duration = Date.now() - startTime;
333
- return {
334
- success: false,
335
- error: (0, type_guards_js_1.isError)(error) ? error.message : 'Doctor command failed',
336
- duration
337
- };
338
- }
339
- }
340
- // VALIDATE command - use bundled validate
341
- if (command === 'validate') {
342
- try {
343
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
344
- const projectPath = pathArgs[0] || this.workingDirectory;
345
- const result = await (0, validate_js_1.validateFafFile)(projectPath, { json: true });
346
- const duration = Date.now() - startTime;
347
- return {
348
- success: result.success,
349
- data: result,
350
- duration
351
- };
352
- }
353
- catch (error) {
354
- const duration = Date.now() - startTime;
355
- return {
356
- success: false,
357
- error: (0, type_guards_js_1.isError)(error) ? error.message : 'Validate command failed',
358
- duration
359
- };
360
- }
361
- }
362
- // AUDIT command - use bundled audit
363
- if (command === 'audit') {
364
- try {
365
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
366
- const projectPath = pathArgs[0] || this.workingDirectory;
367
- const result = await (0, audit_js_1.auditFafFile)(projectPath, { json: true });
368
- const duration = Date.now() - startTime;
369
- return {
370
- success: result.success,
371
- data: result,
372
- duration
373
- };
374
- }
375
- catch (error) {
376
- const duration = Date.now() - startTime;
377
- return {
378
- success: false,
379
- error: (0, type_guards_js_1.isError)(error) ? error.message : 'Audit command failed',
380
- duration
381
- };
382
- }
383
- }
384
- // UPDATE command - use bundled update
385
- if (command === 'update') {
386
- try {
387
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
388
- const projectPath = pathArgs[0] || this.workingDirectory;
389
- const result = await (0, update_js_1.updateFafFile)(projectPath, { json: true });
390
- const duration = Date.now() - startTime;
391
- return {
392
- success: result.success,
393
- data: result,
394
- duration
395
- };
396
- }
397
- catch (error) {
398
- const duration = Date.now() - startTime;
399
- return {
400
- success: false,
401
- error: (0, type_guards_js_1.isError)(error) ? error.message : 'Update command failed',
402
- duration
403
- };
404
- }
405
- }
406
- // MIGRATE command - use bundled migrate
407
- if (command === 'migrate') {
408
- try {
409
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
410
- const projectPath = pathArgs[0] || this.workingDirectory;
411
- const force = args.includes('--force');
412
- const result = await (0, migrate_js_1.migrateFafFile)(projectPath, { force, json: true });
413
- const duration = Date.now() - startTime;
414
- return {
415
- success: result.success,
416
- data: result,
417
- duration
418
- };
419
- }
420
- catch (error) {
421
- const duration = Date.now() - startTime;
422
- return {
423
- success: false,
424
- error: (0, type_guards_js_1.isError)(error) ? error.message : 'Migrate command failed',
425
- duration
426
- };
427
- }
428
- }
429
- // INNIT command - use bundled innit (British init)
430
- if (command === 'innit') {
431
- try {
432
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
433
- const projectPath = pathArgs[0] || this.workingDirectory;
434
- const force = args.includes('--force');
435
- const result = await (0, innit_js_1.innitFafFile)(projectPath, { force });
436
- const duration = Date.now() - startTime;
437
- return {
438
- success: result.success,
439
- data: result,
440
- duration
441
- };
442
- }
443
- catch (error) {
444
- const duration = Date.now() - startTime;
445
- return {
446
- success: false,
447
- error: (0, type_guards_js_1.isError)(error) ? error.message : 'Innit command failed',
448
- duration
449
- };
450
- }
451
- }
452
- // QUICK command - use bundled quick
453
- if (command === 'quick') {
454
- try {
455
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
456
- const projectPath = pathArgs[0] || this.workingDirectory;
457
- const input = pathArgs[1]; // optional input string
458
- const force = args.includes('--force');
459
- const json = args.includes('--json');
460
- const result = await (0, quick_js_1.quickCommand)(projectPath, input, { force, json });
461
- const duration = Date.now() - startTime;
462
- return {
463
- success: result.success,
464
- data: result,
465
- duration
466
- };
467
- }
468
- catch (error) {
469
- const duration = Date.now() - startTime;
470
- return {
471
- success: false,
472
- error: (0, type_guards_js_1.isError)(error) ? error.message : 'Quick command failed',
473
- duration
474
- };
475
- }
476
- }
477
- // HUMAN command - use bundled human (add/set human_context)
478
- if (command === 'human' || command === 'human-add') {
479
- try {
480
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
481
- const projectPath = pathArgs[0] || this.workingDirectory;
482
- // Extract YAML from args if provided
483
- const yamlArg = args.find(arg => arg.startsWith('--yaml='));
484
- const yaml = yamlArg ? yamlArg.substring(7) : undefined;
485
- // Extract field/value for single field mode
486
- const fieldArg = args.find(arg => arg.startsWith('--field='));
487
- const valueArg = args.find(arg => arg.startsWith('--value='));
488
- const field = fieldArg ? fieldArg.substring(8) : undefined;
489
- const value = valueArg ? valueArg.substring(8) : undefined;
490
- const result = await (0, human_js_1.humanAddCommand)(projectPath, { yaml, field, value });
491
- const duration = Date.now() - startTime;
492
- return {
493
- success: result.success,
494
- data: result,
495
- duration
496
- };
497
- }
498
- catch (error) {
499
- const duration = Date.now() - startTime;
500
- return {
501
- success: false,
502
- error: (0, type_guards_js_1.isError)(error) ? error.message : 'Human command failed',
503
- duration
504
- };
505
- }
151
+ return { success: false, error: 'Command must be a non-empty string', duration: 0 };
506
152
  }
507
- // HUMAN-SET command - set single field
508
- if (command === 'human-set') {
509
- try {
510
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
511
- const projectPath = pathArgs[0] || this.workingDirectory;
512
- const field = pathArgs[1];
513
- const value = pathArgs[2];
514
- if (!field || !value) {
153
+ const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
154
+ const projectPath = pathArgs[0] || this.workingDirectory;
155
+ const actionArg = args.find(arg => arg.startsWith('--action='));
156
+ const force = args.includes('--force');
157
+ const merge = args.includes('--merge');
158
+ try {
159
+ switch (command) {
160
+ case 'sync': {
161
+ const result = await (0, sync_js_1.syncFafFile)(projectPath, { auto: args.includes('--auto'), json: true });
162
+ return this.outcome(result, 'Sync command failed', startTime);
163
+ }
164
+ case 'bi-sync':
165
+ case 'bisync': {
166
+ const result = await (0, bi_sync_js_1.syncBiDirectional)(projectPath, {
167
+ json: true,
168
+ agents: args.includes('--agents'),
169
+ cursor: args.includes('--cursor'),
170
+ gemini: args.includes('--gemini'),
171
+ all: args.includes('--all'),
172
+ });
173
+ return this.outcome(result, 'Bi-sync command failed', startTime);
174
+ }
175
+ case 'agents': {
176
+ const action = actionArg ? actionArg.substring(9) : 'sync';
177
+ const result = action === 'import' ? await (0, agents_js_1.agentsImportCommand)(projectPath, { merge })
178
+ : action === 'export' ? await (0, agents_js_1.agentsExportCommand)(projectPath, { force })
179
+ : await (0, agents_js_1.agentsSyncCommand)(projectPath);
180
+ return this.outcome(result, 'Agents command failed', startTime);
181
+ }
182
+ case 'cursor': {
183
+ const action = actionArg ? actionArg.substring(9) : 'sync';
184
+ const result = action === 'import' ? await (0, cursor_js_1.cursorImportCommand)(projectPath, { merge })
185
+ : action === 'export' ? await (0, cursor_js_1.cursorExportCommand)(projectPath, { force })
186
+ : await (0, cursor_js_1.cursorSyncCommand)(projectPath);
187
+ return this.outcome(result, 'Cursor command failed', startTime);
188
+ }
189
+ case 'gemini': {
190
+ const action = actionArg ? actionArg.substring(9) : 'sync';
191
+ const result = action === 'import' ? await (0, gemini_js_1.geminiImportCommand)(projectPath, { merge })
192
+ : action === 'export' ? await (0, gemini_js_1.geminiExportCommand)(projectPath, { force })
193
+ : await (0, gemini_js_1.geminiSyncCommand)(projectPath);
194
+ return this.outcome(result, 'Gemini command failed', startTime);
195
+ }
196
+ case 'conductor': {
197
+ const action = actionArg ? actionArg.substring(9) : 'import';
198
+ const result = action === 'export'
199
+ ? await (0, conductor_js_1.conductorExportCommand)(projectPath, { force })
200
+ : await (0, conductor_js_1.conductorImportCommand)(projectPath, { merge });
201
+ return this.outcome(result, 'Conductor command failed', startTime);
202
+ }
203
+ case 'git': {
204
+ const url = args[0];
205
+ const outputPath = args[1]; // optional
206
+ if (!url) {
207
+ return { success: false, error: 'URL is required', duration: Date.now() - startTime };
208
+ }
209
+ const result = await (0, git_context_js_1.gitContextCommand)(url, outputPath);
210
+ return this.outcome(result, 'Git command failed', startTime);
211
+ }
212
+ default:
515
213
  return {
516
214
  success: false,
517
- error: 'Usage: human-set <field> <value>',
518
- duration: Date.now() - startTime
215
+ error: `Unknown engine command '${command}'. Every faf-mcp tool runs in-process; there is no CLI to fall back to.`,
216
+ duration: Date.now() - startTime,
519
217
  };
520
- }
521
- const result = await (0, human_js_1.humanSetCommand)(projectPath, field, value);
522
- const duration = Date.now() - startTime;
523
- return {
524
- success: result.success,
525
- data: result,
526
- duration
527
- };
528
- }
529
- catch (error) {
530
- const duration = Date.now() - startTime;
531
- return {
532
- success: false,
533
- error: (0, type_guards_js_1.isError)(error) ? error.message : 'Human-set command failed',
534
- duration
535
- };
536
- }
537
- }
538
- // README command - extract context from README.md
539
- if (command === 'readme' || command === 'readme-extract') {
540
- try {
541
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
542
- const projectPath = pathArgs[0] || this.workingDirectory;
543
- const result = await (0, readme_js_1.readmeExtractCommand)(projectPath);
544
- const duration = Date.now() - startTime;
545
- return {
546
- success: result.success,
547
- data: result,
548
- duration
549
- };
550
- }
551
- catch (error) {
552
- const duration = Date.now() - startTime;
553
- return {
554
- success: false,
555
- error: (0, type_guards_js_1.isError)(error) ? error.message : 'README extract command failed',
556
- duration
557
- };
558
- }
559
- }
560
- // README-MERGE command - extract and merge into .faf
561
- if (command === 'readme-merge') {
562
- try {
563
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
564
- const projectPath = pathArgs[0] || this.workingDirectory;
565
- // Check for overwrite flag
566
- const overwrite = args.includes('--overwrite');
567
- const result = await (0, readme_js_1.readmeMergeCommand)(projectPath, { overwrite });
568
- const duration = Date.now() - startTime;
569
- return {
570
- success: result.success,
571
- data: result,
572
- duration
573
- };
574
- }
575
- catch (error) {
576
- const duration = Date.now() - startTime;
577
- return {
578
- success: false,
579
- error: (0, type_guards_js_1.isError)(error) ? error.message : 'README merge command failed',
580
- duration
581
- };
582
- }
583
- }
584
- // ============================================================================
585
- // v4.5.0 INTEROP COMMANDS
586
- // ============================================================================
587
- // AGENTS command - import/export/sync AGENTS.md
588
- if (command === 'agents') {
589
- try {
590
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
591
- const projectPath = pathArgs[0] || this.workingDirectory;
592
- const actionArg = args.find(arg => arg.startsWith('--action='));
593
- const action = actionArg ? actionArg.substring(9) : 'sync';
594
- const force = args.includes('--force');
595
- const merge = args.includes('--merge');
596
- let result;
597
- if (action === 'import') {
598
- result = await (0, agents_js_1.agentsImportCommand)(projectPath, { merge });
599
- }
600
- else if (action === 'export') {
601
- result = await (0, agents_js_1.agentsExportCommand)(projectPath, { force });
602
- }
603
- else {
604
- result = await (0, agents_js_1.agentsSyncCommand)(projectPath);
605
- }
606
- return { success: result.success, data: result, duration: Date.now() - startTime };
607
- }
608
- catch (error) {
609
- return { success: false, error: (0, type_guards_js_1.isError)(error) ? error.message : 'Agents command failed', duration: Date.now() - startTime };
610
- }
611
- }
612
- // CURSOR command - import/export/sync .cursorrules
613
- if (command === 'cursor') {
614
- try {
615
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
616
- const projectPath = pathArgs[0] || this.workingDirectory;
617
- const actionArg = args.find(arg => arg.startsWith('--action='));
618
- const action = actionArg ? actionArg.substring(9) : 'sync';
619
- const force = args.includes('--force');
620
- const merge = args.includes('--merge');
621
- let result;
622
- if (action === 'import') {
623
- result = await (0, cursor_js_1.cursorImportCommand)(projectPath, { merge });
624
- }
625
- else if (action === 'export') {
626
- result = await (0, cursor_js_1.cursorExportCommand)(projectPath, { force });
627
- }
628
- else {
629
- result = await (0, cursor_js_1.cursorSyncCommand)(projectPath);
630
- }
631
- return { success: result.success, data: result, duration: Date.now() - startTime };
632
- }
633
- catch (error) {
634
- return { success: false, error: (0, type_guards_js_1.isError)(error) ? error.message : 'Cursor command failed', duration: Date.now() - startTime };
635
- }
636
- }
637
- // GEMINI command - import/export/sync GEMINI.md
638
- if (command === 'gemini') {
639
- try {
640
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
641
- const projectPath = pathArgs[0] || this.workingDirectory;
642
- const actionArg = args.find(arg => arg.startsWith('--action='));
643
- const action = actionArg ? actionArg.substring(9) : 'sync';
644
- const force = args.includes('--force');
645
- const merge = args.includes('--merge');
646
- let result;
647
- if (action === 'import') {
648
- result = await (0, gemini_js_1.geminiImportCommand)(projectPath, { merge });
649
- }
650
- else if (action === 'export') {
651
- result = await (0, gemini_js_1.geminiExportCommand)(projectPath, { force });
652
- }
653
- else {
654
- result = await (0, gemini_js_1.geminiSyncCommand)(projectPath);
655
- }
656
- return { success: result.success, data: result, duration: Date.now() - startTime };
657
- }
658
- catch (error) {
659
- return { success: false, error: (0, type_guards_js_1.isError)(error) ? error.message : 'Gemini command failed', duration: Date.now() - startTime };
660
- }
661
- }
662
- // CONDUCTOR command - import/export conductor/
663
- if (command === 'conductor') {
664
- try {
665
- const pathArgs = args.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
666
- const projectPath = pathArgs[0] || this.workingDirectory;
667
- const actionArg = args.find(arg => arg.startsWith('--action='));
668
- const action = actionArg ? actionArg.substring(9) : 'import';
669
- const force = args.includes('--force');
670
- const merge = args.includes('--merge');
671
- let result;
672
- if (action === 'export') {
673
- result = await (0, conductor_js_1.conductorExportCommand)(projectPath, { force });
674
- }
675
- else {
676
- result = await (0, conductor_js_1.conductorImportCommand)(projectPath, { merge });
677
- }
678
- return { success: result.success, data: result, duration: Date.now() - startTime };
679
- }
680
- catch (error) {
681
- return { success: false, error: (0, type_guards_js_1.isError)(error) ? error.message : 'Conductor command failed', duration: Date.now() - startTime };
682
- }
683
- }
684
- // GIT command - generate .faf from GitHub repo
685
- if (command === 'git') {
686
- try {
687
- const url = args[0];
688
- const outputPath = args[1]; // optional
689
- if (!url) {
690
- return { success: false, error: 'URL is required', duration: Date.now() - startTime };
691
- }
692
- const result = await (0, git_context_js_1.gitContextCommand)(url, outputPath);
693
- return { success: result.success, data: result, duration: Date.now() - startTime };
694
- }
695
- catch (error) {
696
- return { success: false, error: (0, type_guards_js_1.isError)(error) ? error.message : 'Git command failed', duration: Date.now() - startTime };
697
- }
698
- }
699
- // ============================================================================
700
- // FALLBACK: Shell out to CLI for commands not yet bundled
701
- // ============================================================================
702
- // Check if CLI is available
703
- if (!this.detectedCliPath) {
704
- const duration = Date.now() - startTime;
705
- return {
706
- success: false,
707
- error: `FAF CLI not detected. Command '${command}' requires faf-cli.\n\nINSTALLATION ORDER:\n 1️⃣ npm install -g faf-cli\n 2️⃣ npm install -g faf-mcp\n\nAfter installing faf-cli, restart your MCP host.`,
708
- duration
709
- };
710
- }
711
- // Sanitize arguments to prevent injection
712
- const sanitizedArgs = args.map(arg => typeof arg === 'string' ? arg.replace(/[;&|`$(){}[\]]/g, '') : '');
713
- try {
714
- // Use detected absolute path to CLI
715
- const fullCommand = `"${this.detectedCliPath}" ${command} ${sanitizedArgs.join(' ')}`;
716
- const { stdout, stderr } = await execAsync(fullCommand, {
717
- env: getEnhancedEnv(),
718
- timeout: this.timeout,
719
- maxBuffer: 1024 * 1024, // 1MB buffer limit
720
- cwd: this.workingDirectory
721
- });
722
- const duration = Date.now() - startTime;
723
- if (stderr?.trim()) {
724
- console.warn(`FAF CLI warning: ${stderr.trim()}`);
725
218
  }
726
- return {
727
- success: true,
728
- data: this.parseOutput(stdout),
729
- duration
730
- };
731
219
  }
732
220
  catch (error) {
733
- const duration = Date.now() - startTime;
734
- let errorMessage = 'Unknown error occurred';
735
- if ((0, type_guards_js_1.isError)(error)) {
736
- errorMessage = error.message;
737
- // Handle specific error codes
738
- if ('code' in error) {
739
- if (error.code === 'ETIMEDOUT') {
740
- errorMessage = `Command timed out after ${this.timeout}ms`;
741
- }
742
- else if (error.code === 'ENOENT') {
743
- errorMessage = `FAF CLI not found at ${this.detectedCliPath}. Please reinstall: npm install -g faf-cli`;
744
- }
745
- }
746
- // Handle signal termination
747
- if ('signal' in error && error.signal === 'SIGTERM') {
748
- errorMessage = 'Command was terminated';
749
- }
750
- }
751
- console.error(`FAF CLI error: ${errorMessage}`);
752
- return {
753
- success: false,
754
- error: errorMessage,
755
- duration
756
- };
757
- }
758
- }
759
- parseOutput(output) {
760
- if (!output || output.trim() === '') {
761
- return { output: '' };
762
- }
763
- try {
764
- return JSON.parse(output);
765
- }
766
- catch {
767
- return { output: output.trim() };
768
- }
769
- }
770
- // Method to check if FAF CLI is available
771
- async checkHealth() {
772
- try {
773
- const result = await this.callEngine('--version');
774
- return result.success;
775
- }
776
- catch {
777
- return false;
221
+ return this.failure(error, `${command} command failed`, startTime);
778
222
  }
779
223
  }
780
224
  // Get the current working directory used by the adapter
@@ -800,14 +244,6 @@ class FafEngineAdapter {
800
244
  getEnginePath() {
801
245
  return this.enginePath;
802
246
  }
803
- // Get CLI detection info for debugging
804
- getCliInfo() {
805
- return {
806
- detected: this.detectedCliPath !== null,
807
- path: this.detectedCliPath || undefined,
808
- version: this.cliVersion
809
- };
810
- }
811
247
  }
812
248
  exports.FafEngineAdapter = FafEngineAdapter;
813
249
  //# sourceMappingURL=engine-adapter.js.map